How would I write a simple LINQ to SQL extension method called "IsActive" which would contain a few basic criteria checks of a few different fields, so that I could reuse this "IsActive" logic all over the place without duplicating the logic.
For example, I would like to be able to do something like this:
return db.Listings.Where(x => x.IsActive())
And IsActive would be something like:
public bool IsActive(Listing SomeListing)
{
if(SomeListing.Approved==true && SomeListing.Deleted==false)
return true;
else
return false;
}
Otherwise, I am going to have to duplicate the same old where criteria in a million different queries right throughout my system.
Note: method must render in SQL..
Good question, there is a clear need to be able to define a re-useable filtering expression to avoid redundantly specifying logic in disparate queries.
This method will generate a filter you can pass to the Where method.
public Expression<Func<Listing, bool>> GetActiveFilter()
{
return someListing => someListing.Approved && !someListing.Deleted;
}
Then later, call it by:
Expression<Func<Filter, bool>> filter = GetActiveFilter()
return db.Listings.Where(filter);
Since an Expression<Func<T, bool>> is used, there will be no problem translating to sql.
Here's an extra way to do this:
public static IQueryable<Filter> FilterToActive(this IQueryable<Filter> source)
{
var filter = GetActiveFilter()
return source.Where(filter);
}
Then later,
return db.Listings.FilterToActive();
You can use a partial class to achieve this.
In a new file place the following:
namespace Namespace.Of.Your.Linq.Classes
{
public partial class Listing
{
public bool IsActive()
{
if(this.Approved==true && this.Deleted==false)
return true;
else
return false;
}
}
}
Since the Listing object (x in your lambda) is just an object, and Linq to SQL defines the generated classes as partial, you can add functionality (properties, methods, etc) to the generated classes using partial classes.
I don't believe the above will be rendered into the SQL query. If you want to do all the logic in the SQL Query, I would recommend making a method that calls the where method and just calling that when necessary.
EDIT
Example:
public static class DataManager
{
public static IEnumerable<Listing> GetActiveListings()
{
using (MyLinqToSqlDataContext ctx = new MyLinqToSqlDataContext())
{
return ctx.Listings.Where(x => x.Approved && !x.Deleted);
}
}
}
Now, whenever you want to get all the Active Listings, just call DataManager.GetActiveListings()
public static class ExtensionMethods
{
public static bool IsActive( this Listing SomeListing)
{
if(SomeListing.Approved==true && SomeListing.Deleted==false)
return true;
else
return false;
}
}
Late to the party here, but yet another way to do it that I use is:
public static IQueryable<Listing> GetActiveListings(IQueryable<Listing> listings)
{
return listings.Where(x => x.Approved && !x.Deleted);
}
and then
var activeListings = GetActiveListings(ctx.Listings);
Related
I am trying to write test case but stuck with this error. How to fix this error ?
#Override
public boolean isDuplicateSystemDetail(SystemFormBean systemFormBean){
List<BrmSystem> list = systemDao.isDuplicateSystemDetail(systemFormBean);
if(CollectionUtils.isNotEmpty(list)){
return true;
}else{
return false;
}
}
---------------------------------------------------------------------------
#Test
public void isDuplicateSystemDetail_Should_Return_True(){
List<BrmSystem> list = new ArrayList<BrmSystem>();
BrmSystem brmSystem = new BrmSystem();
SystemFormBean systemFormBean = new SystemFormBean();
brmSystem.setSystemName("Test");
list.add(brmSystem);
when(systemDao.isDuplicateSystemDetail(systemFormBean)).thenReturn(list);
}
Probably SystemFormBean class doesn't override equals(). So when isDuplicateSystemDetail(systemFormBean) invokes, it has another object of this class as a parameter which is not the same as the one you've created manually (by default Object.equals() compares memory adresses which would be false in your case).
Try to override equals() to compare by f.e. actual fields of SystemFormBean or rewrite "when" clause as
systemDao.isDuplicateSystemDetail(Mockito.any(SystemFormBean.class))
I've inherited a system that uses the Castle Windsor IRepository pattern to abstract away from the DAL which is LinqToSQL.
The main problem that I can see, is that IRepository only implements IEnumerable. So even the simplest of queries have to load ALL the data from the datatable, to return a single object.
Current usage is as follows
using (IUnitOfWork context2 = IocServiceFactory.Resolve<IUnitOfWork>())
{
KpiFormDocumentEntry entry = context2.GetRepository<KpiFormDocumentEntry>().FindById(id, KpiFormDocumentEntry.LoadOptions.FormItem);
And this uses lambda to filter, like so
public static KpiFormDocumentEntry FindById(this IRepository<KpiFormDocumentEntry> source, int id, KpiFormDocumentEntry.LoadOptions loadOptions)
{
return source.Where( qi => qi.Id == id ).LoadWith( loadOptions ).FirstOrDefault();
}
So it becomes a nice extension method.
My Question is, how can I use this same Interface/pattern etc. but also implement IQueryable to properly support LinqToSQL and get some serious performance improvements?
The current implementation/Interfaces for IRepository are as follows
public interface IRepository<T> : IEnumerable<T> where T : class
{
void Add(T entity);
void AddMany(IEnumerable<T> entities);
void Delete(T entity);
void DeleteMany(IEnumerable<T> entities);
IEnumerable<T> All();
IEnumerable<T> Find(Func<T, bool> predicate);
T FindFirst(Func<T, bool> predicate);
}
and then this is implemented by an SqlClientRepository like so
public sealed class SqlClientRepository<T> : IRepository<T> where T : class
{
private readonly Table<T> _source;
internal SqlClientRepository(Table<T> source)
{
if( source == null ) throw new ArgumentNullException( "source", Gratte.Aurora.SHlib.labelText("All_TableIsNull",1) );
_source = source;
}
//removed add delete etc
public IEnumerable<T> All()
{
return _source;
}
public IEnumerator<T> GetEnumerator()
{
return _source.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
The problem at the moment is, in our example above, the .Where is calling 'GetEnumerator', which then loads all rows into memory, and then looks for the one we need.
If I change IRepository to implement IQueryable, I can't implement the three methods needed, as these are not public in the Table class.
I think I should change the SQLClientRepository to be defined like so
public sealed class SqlClientRepository<T> : IQueryable<T>, IRepository<T> where T : class
And then implement the necessary methods, but I can't figure out how to pass the expressions around etc. as they are private members of the Table class, like so
public override Type ElementType
{
get { return _source.ElementType; } //Won't work as ElementType is private
}
public override Expression Expression
{
get { return _source.Expression; } //Won't work as Expression is private
}
public override IQueryProvider Provider
{
get { return _source.Provider; } //Won't work as Provider is private
}
Any help really appreciated to move this from 'iterate through every row in the database after loading it' to 'select x where id=1'!
If you want to expose linq you can stop using the repository pattern and use Linq2Sql directly. The reason to this is that every Linq To Sql provider has it's own custom solutions. So if you expose LINQ you get a leaky abstraction. There is no point in using an abstraction layer then.
Instead of exposing LINQ you got two options:
Implement the specification pattern
Use the repository pattern as I describe here: http://blog.gauffin.org/2013/01/repository-pattern-done-right/
So, while it may not be a true abstraction any longer, the main point was to get the benefit of linq to sql without updating all the queries already written.
so, I made the IRepository implement IQueryable instead of IEnumerable.
then in the SqlClientRepository implementation, I can call AsQueryable() to cast the Table to IQueryable, and then all is good, like so.
Now everywhere somebody has written IRepository().Where(qi => qi.id = id) or similar, it actually passes the ID to sql server and only pulls back one record, instead of all of them, and loops through looking for the correct one.
/// <summary>Provides the ability to query and access entities within a SQL Server data store.</summary>
/// <typeparam name="T">The type of entity in the repository.</typeparam>
public sealed class SqlClientRepository<T> : IRepository<T> where T : class
{
private readonly Table<T> _source;
private readonly IQueryable<T> _sourceQuery;
IQueryable<T> Query()
{
return (IQueryable<T>)_source;
}
public Type ElementType
{
get { return _sourceQuery.GetType(); }
}
public Expression Expression
{
get { return _sourceQuery.Expression; }
}
public IQueryProvider Provider
{
get { return _sourceQuery.Provider; }
}
/// <summary>Initializes a new instance of the <see cref="SqlClientRepository{T}"/> class.</summary>
/// <param name="source">A <see cref="Table{T}"/> to a collection representing the entities from a SQL Server data store.</param>
/// <exception cref="ArgumentNullException"><paramref name="source"/> is a <c>null</c> reference (<c>Nothing</c> in Visual Basic).</exception>
internal SqlClientRepository(Table<T> source)
{
if( source == null ) throw new ArgumentNullException( "source", "All_TableIsNull" ) );
_source = source;
_sourceQuery = _source.AsQueryable();
}
I am trying to figure out a way to pass a collection of include statements into my repository so that I can have it include specific entities. Below is some sample code from my repository.
public TEntity GetById(Guid id)
{
return id != Guid.Empty ? GetSet().Find(id) : null;
}
private IDbSet<TEntity> GetSet()
{
return _unitOfWork.CreateSet<TEntity>();
}
The GetByID method calls the GetSet to return the entity set. I was thinking, if I could somehow pass in a collection of entities to include (via an expression) as part of my GetById, this way I wouldn't have to expose the GetSet to my services. So, something like this:
var entity = _repository.GetById(theId, e => {e.Prop1, e.Prop2, e.Prop3});
I could then pass that expression into my GetSet method and pass it into an include statement. Thoughts?
I have done something like this in my code recently. Would the following work for you?
public TEntity GetById(Guid id, params Expression<Func<TEntity, object>>[] includeProperties)
{
if (id == Guid.Empty) return null;
var set = _unitOfWork.CreateSet<TEntity>();
foreach(var includeProperty in includeProperties)
{
set.Include(includeProperty);
}
return set.First(i => i.Id == id);
}
Then you would call it like this...
var entity = _repository.GetById(theId, e => e.Prop1, e=> e.Prop2, e=> e.Prop3);
I know this doesn't exactly follow your pattern, but I think you could refactor it as required.
I don't think Paige Cook's code will work quite as shown.
I've included a modified version of the code that should work instead:
public TEntity GetById(Guid id, params Expression<Func<TEntity, object>>[] includeProperties)
{
if (id == Guid.Empty) return null;
IQueryable<TEntity> set = _unitOfWork.CreateSet<TEntity>();
foreach(var includeProperty in includeProperties)
{
set = set.Include(includeProperty);
}
return set.First(i => i.Id == id);
}
I only spotted this by tracing the SQL generated by Entity Framework, and realised the original code was only giving the illusion of working, by using lazy-loading to populate the entities specified for inclusion.
There's actually a more terse syntax for applying the Include statements using the LINQ Aggregate method, which is in the blog post linked to. My post also improves the method slightly by having a fall-back to the Find method, when no includes are needed and also shows an example of how to implement a "GetAll" method, using similar syntax.
It's bad idea to store context in non-local space, for many reasons.
I modify Steve's code and get this for my ASP.NET MVC projects:
public aspnet_User FirstElement(Func<aspnet_User, bool> predicate = null, params Expression<Func<aspnet_User, object>>[] includes)
{
aspnet_User result;
using (var context = new DataContext())
{
try
{
var set = context.Users.AsQueryable();
for (int i = 0; i < includes.Count(); i++ )
set = set.Include(includes[i]);
if (predicate != null)
result = set.ToList().FirstOrDefault(predicate);
else
result = set.ToList().FirstOrDefault();
}
catch
{
result = null;
}
}
return result;
}
The include method can be strung together in your linq query like so:
var result = (from i in dbContext.TableName.Include("RelationProperty")
.Include("RelationProperty")
.Include("RelationProperty")
select i);
I just started using LINQ to SQL classes, and really like how this helps me write readable code.
In the documentation, typical examples state that to do custom validation, you create a partial class as so::
partial class Customer
{
partial void OnCustomerIDChanging(string value)
{
if (value=="BADVALUE") throw new NotImplementedException("CustomerID Invalid");
}
}
And similarly for other fields...
And then in the codebehind, i put something like this to display the error message and keep the user on same page so to correct the mistake.
public void CustomerListView_OnItemInserted(object sender, ListViewInsertedEventArgs e)
{
string errorString = "";
if (e.Exception != null)
{
e.KeepInInsertMode = true;
errorString += e.Exception.Message;
e.ExceptionHandled = true;
}
else errorString += "Successfully inserted Customer Data" + "\n";
errorMessage.Text = errorString;
}
Okay, that's easy, but then it stops validating the rest of the fields as soon as the first Exception is thrown!! Mean if the user made mode than one mistake, she/he/it will only be notified of the first error.
Is there another way to check all the input and show the errors in each ?
Any suggestions appreciated, thanks.
This looks like a job for the Enterprise Library Validation Application Block (VAB). VAB has been designed to return all errors. Besides this, it doesn't thrown an exception, so you can simply ask it to validate the type for you.
When you decide to use the VAB, I advise you to -not- use the OnXXXChanging and OnValidate methods of LINQ to SQL. It's best to override the SubmitChange(ConflictMode) method on the DataContext class to call into VAB's validation API. This keeps your validation logic out of your business entities, which keeps your entities clean.
Look at the following example:
public partial class NorthwindDataContext
{
public ValidationResult[] Validate()
{
return invalidResults = (
from entity in this.GetChangedEntities()
let type = entity.GetType()
let validator = ValidationFactory.CreateValidator(type)
let results = validator.Validate(entity)
where !results.IsValid
from result in results
select result).ToArray();
}
public override void SubmitChanges(ConflictMode failureMode)
{
ValidationResult[] this.Validate();
if (invalidResults.Length > 0)
{
// You should define this exception type
throw new ValidationException(invalidResults);
}
base.SubmitChanges(failureMode);
}
private IEnumerable<object> GetChangedEntities()
{
ChangeSet changes = this.GetChangeSet();
return changes.Inserts.Concat(changes.Updates);
}
}
[Serializable]
public class ValidationException : Exception
{
public ValidationException(IEnumerable<ValidationResult> results)
: base("There are validation errors.")
{
this.Results = new ReadOnlyCollection<ValidationResult>(
results.ToArray());
}
public ReadOnlyCollection<ValidationResult> Results
{
get; private set;
}
}
Calling the Validate() method will return a collection of all errors, but rather than calling Validate(), I'd simply call SubmitChanges() when you're ready to persist. SubmitChanges() will now check for errors and throw an exception when one of the entities is invalid. Because the list of errors is sent to the ValidationException, you can iterate over the errors higher up the call stack, and present them to the user, as follows:
try
{
db.SubmitChanges();
}
catch (ValidationException vex)
{
ShowErrors(vex.ValidationErrors);
}
private static void ShowErrors(IEnumerable<ValidationResult> errors)
{
foreach(var error in errors)
{
Console.WriteLine("{0}: {1}", error.Key, error.message);
}
}
When you use this approach you make sure that your entities are always validated before saving them to the database
Here is a good article that explains how to integrate VAB with LINQ to SQL. You should definitely read it if you want to use VAB with LINQ to SQL.
Not with LINQ. Presumably you would validate the input before giving it to LINQ.
What you're seeing is natural behaviour with exceptions.
I figured it out. Instead of throwing an exception at first failed validation, i store an error message in a class with static variable. to do this, i extend the DataContext class like this::
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
/// <summary>
/// Summary description for SalesClassesDataContext
/// </summary>
public partial class SalesClassesDataContext
{
public class ErrorBox
{
private static List<string> Messages = new List<string>();
public void addMessage(string message)
{
Messages.Add(message);
}
public List<string> getMessages()
{
return Messages;
}
}
}
in the classes corresponding to each table, i would inherit the newly defined class like this::
public partial class Customer : SalesClassesDataContext.ErrorBox
only in the function OnValidate i would throw an exception in case the number of errors is not 0. Hence not attempting to insert, and keeping the user on same input page, without loosing the data they entered.
I have a static Settings class where my application can retrieve settings from. The problem is that some of these settings are strings, while others are ints or numbers. Example:
package
{
public final class Settings
{
public static function retrieve(msg:String)
{
switch (msg)
{
case "register_link":
return "http://test.com/client/register.php";
break;
case "time_limit":
return 50;
break;
}
}
}
}
Now, in the first case it should send a string and in the second a uint. However, how do I set this in the function declarement? Instead of eg. function retrieve(msg:String):String or ...:uint? If I don't set any data type, I get a warning.
HanClinto has answered your question, but I would like to also just make a note of another possible solution that keeps the return types, typed. I also find it to be a cleaner solution.
Rather than a static retrieve function, you could just use static consts, such as:
package
{
public final class Settings
{
public static const REGISTER_LINK:String = "my link";
public static const TIME_LIMIT:uint= 50;
}
}
And so forth. It's personal preference, but I thought I would throw it out there.
Use *
public static function retrieve(msg:String):*
{
if (msg == "age") {
return 23;
} else {
return "hi!";
}
}