Entity Framework : query vs foreach - c#

If it okay to use foreach for a simple query like this? Or should I always use the query thing ?
public static Staff GetTeacher(Context context, int staffId)
{
foreach (Staff staff in context.Staff)
{
if(staff.StaffID == staffId)
{
return staff;
}
}
return null;
}
public static object GetTeacher(Context context, int staffId)
{
var staff = from teacher in context.Staff
where teacher.StaffID == staffId
select new
{
Id = teacher.StaffID,
Teacher = teacher.FirstName + " " + teacher.LastName
};
return staff;
}

The foreach will loop over every record in your database table until it finds a match, meaning it might eventually pull every single record into memory. That could be incredibly slow.
The Linq query will construct an SQL statement that only pulls out the relevant record(s).
So the second option is far better. However, it looks like you tried to fix the fact your second query give an enumerable list of staff object by making the function return an object. Instead, you can make the entire thing look much nicer, something like this:
public static Staff GetTeacher(Context context, int staffId)
{
return context.Staff.Single(s => s.StaffID == staffId);
}
This will be the most efficient method. It will throw an exception if there is no matching staffId in the database. That might be a good thing for you. If not, change it to use SingleOrDefault instead of Single.
Side note: I'm concerned about the method being static. This suggests the DbContext might be shared or long-lived which are both bad things.

Related

Running inline SQL with Entity Framework 5 and returning tracked Entities

How can I execute a command such as:
SELECT * FROM CATS
That behaves exactly as if I'd done myContext.Cats.Where(c => true); ?
Google suggested context.Database.ExecuteSqlCommand() but that returns an int. There is also context.Database.SqlQuery which looks promising, but it says that entities returned are not tracked, which I suspect is important (I'm not really familiar with how EF works in terms of tracking things).
It suggests using System.Data.Entity.DbSet<TEntity>.SqlQuery(Object[]) to track it, but I'm not entirely sure what this means or how to implement it.
In addition to make it even more confusing I want to write a generic method to allow me to execute the specific query against any table.
Here's a rough example of what I'd like in pseudocode
public DbSet<T> ExecuteSelect<T>(DbContext context, string table)
{
DbSet<T> entities = context.RunSql("SELECT * FROM " + table);
return entities;
}
Any ideas?
Accoring to this: http://msdn.microsoft.com/en-us/data/jj592907.aspx you want the following:
public IEnumerable<T> ExecuteSelect<T>(DbContext context, string table)
{
IEnumerable<T> entities = context.Set<T>.SqlQuery("SELECT * FROM " + table).ToList();
return entities;
}
myContext.Cats.Where(c => true) returns IQueriable<Cat> (not DbSet)
BUT
Your returned set will actually be finalized already (eg you cant add extra bits to your query later) so having it Queriable is misdirecting.
You can execute sql queries directly as follows :
private int DeleteData()
{
using (var ctx = new MyEntities(this.ConnectionString))
{
if (ctx != null)
{
//Delete command
return ctx.ExecuteStoreCommand("DELETE FROM ALARM WHERE AlarmID > 100");
}
}
return 0;
}
For select we may use
using (var context = new MyContext())
{
var blogs = context.MyTable.SqlQuery("SELECT * FROM dbo.MyTable").ToList();
}

SQL "not in" syntax for Entity Framework 4.1

I have a simple issue with Entity Framework syntax for the "not in" SQL equivalent. Essentially, I want to convert the following SQL syntax into Entity Framework syntax:
select ID
from dbo.List
where ID not in (list of IDs)
Here is a method that I use for looking up a single record:
public static List GetLists(int id)
{
using (dbInstance db = new dbInstance())
{
return db.Lists.Where(m => m.ID == id);
}
}
Here is a pseudo-method that I want to use for this:
public static List<List> GetLists(List<int> listIDs)
{
using (dbInstance db = new dbInstance())
{
return db.Lists.Where(**** What Goes Here ****).ToList();
}
}
Can anyone give me pointers as to what goes in the Where clause area? I read some forums about this and saw mention of using .Contains() or .Any(), but none of the examples were a close enough fit.
Give this a go...
public static List<List> GetLists(List<int> listIDs)
{
using (dbInstance db = new dbInstance())
{
// Use this one to return List where IS NOT IN the provided listIDs
return db.Lists.Where(x => !listIDs.Contains(x.ID)).ToList();
// Or use this one to return List where IS IN the provided listIDs
return db.Lists.Where(x => listIDs.Contains(x.ID)).ToList();
}
}
These will turn into approximately the following database queries:
SELECT [Extent1].*
FROM [dbo].[List] AS [Extent1]
WHERE NOT ([Extent1].[ID] IN (<your,list,of,ids>))
or
SELECT [Extent1].*
FROM [dbo].[List] AS [Extent1]
WHERE [Extent1].[ID] IN (<your,list,of,ids>)
respectively.
This one requires you to think backwards a little bit. Instead of asking if the value is not in some list of ids, you have to ask of some list of id's does not contain the value. Like this
int[] list = new int[] {1,2,3}
Result = (from x in dbo.List where list.Contains(x.id) == false select x);
Try this for starters ...
m => !listIDs.Contains(m.ID)
This might be a way to do what you want:
// From the method you provided, with changes...
public static List GetLists(int[] ids) // Could be List<int> or other =)
{
using (dbInstance db = new dbInstance())
{
return db.Lists.Where(m => !ids.Contains(m.ID));
}
}
However I've found that doing so might raise error on some scenarios, specially when the list is too big and connection is somewhat slow.
Remember to check everything else BEFORE so this filter might have less values to check.
Also remember that Linq does not populate the variable when you build your filter/query (at least not by default). If you're going to iterate for each record, remember to call a ToList() or ToArray() method before, unless each record has 500MB or more...

How to optimise this short and simple code (includes a best practice question)

Here is a question I frequently ask myself. Here is a code with no repeated code:
private static void delete(Guid teamID, Guid repID)
{
using (var context = AccesDataRépart.GetNewContext())
{
Team_Representant teamRepresentant = getTeamRep(teamID, repID);
if (teamRepresentant != null)
context.Team_Representant.DeleteOnSubmit(teamRepresentant);
context.SubmitChanges();
}
}
private static Team_Representant getTeamRep(Guid teamID, Guid repID)
{
using (var context = AccesDataRépart.GetNewContext())
{
return (from c in context.Team_Representant
where c.RepID == repID &&
c.TeamID == teamID
select c).FirstOrDefault();
}
}
It is normal to have a getTeamRep function, it is used very often. On the other hand, I don't repeat the query it contains in the Delete function because it would generate extra steps and would generally be slower.
What do you do in such case? Do you repeat the getTeamRep linq query in the Delete function or do you accept this extra workload?
Thanks!
I never do anything twice :). Make a variable to hold the result of getTeamRep.
If you've never tried it before, get rid of your static stuff and make these all instance methods. Have a Team class and a Rep class, and let the Teams contain their Reps. It might be more fun this way, and it tends to prevent the whole problem of looking up the same object twice.
It's a matter of preference. I find instance methods more elegant in most cases, because there are fewer parameters:
Team team = new Team(teamID);
team.Delete(repID);

Genericising one class to handle multiple types

I have a series of about 30 lookup tables in my database schema, all with the same layout (and I would prefer to keep them as separate tables rather than one lookup table), and thus my Linq2SQL context has 30 entities for these lookup tables.
I have a standard class that I would use for CRUD operations on each of these 30 entites, for example:
public class ExampleAttributes : IAttributeList
{
#region IAttributeList Members
public bool AddItem(string Item, int SortOrder)
{
MyDataContext context = ContextHelper.GetContext();
ExampleAttribute a = new ExampleAttribute();
a.Name = Item;
a.SortOrder = SortOrder;
context.ExampleAttributes.InsertOnSubmit(a);
try
{
context.SubmitChanges();
return true;
}
catch
{
return false;
}
}
public bool DeleteItem(int Id)
{
MyDataContext context = ContextHelper.GetContext();
ExampleAttribute a = (from m in context.ExampleAttributes
where m.Id == Id
select m).FirstOrDefault();
if (a == null)
return true;
// Make sure nothing is using it
int Count = (from m in context.Businesses
where m.ExampleAttributeId == a.Id
select m).Count();
if (Count > 0)
return false;
// Delete the item
context.ExampleAttributes.DeleteOnSubmit(a);
try
{
context.SubmitChanges();
return true;
}
catch
{
return false;
}
}
public bool UpdateItem(int Id, string Item, int SortOrder)
{
MyDataContext context = ContextHelper.GetContext();
ExampleAttribute a = (from m in context.ExampleAttributes
where m.Id == Id
select m).FirstOrDefault();
a.Name = Item;
a.SortOrder = SortOrder;
try
{
context.SubmitChanges();
return true;
}
catch
{
return false;
}
}
public String GetItem(int Id)
{
MyDataContext context = ContextHelper.GetContext();
var Attribute = (from a in context.ExampleAttributes
where a.Id == Id
select a).FirstOrDefault();
return Attribute.Name;
}
public Dictionary<int, string> GetItems()
{
Dictionary<int, string> Attributes = new Dictionary<int, string>();
MyDataContext context = ContextHelper.GetContext();
context.ObjectTrackingEnabled = false;
Attributes = (from o in context.ExampleAttributes orderby o.Name select new { o.Id, o.Name }).AsEnumerable().ToDictionary(k => k.Id, v => v.Name);
return Attributes;
}
#endregion
}
I could replicate this class 30 times with very minor changes for each lookup entity, but that seems messy somehow - so can this class be genericised so I can also pass it the type I want, and have it handle internally the type differences in the linq queries? That way, I have one class to make additions to, one class to bug fix et al - seems the way that it should be done.
UPDATE:
Andrews answer below gave me the option that I was really looking at while thinking about the question (passing the type in) but I need more clarification on how to genericise the linq queries. Can anyone clarify this?
Cheers
Moo
There are a couple things you can try.
One is to define an interface that has all the relevant fields that the thirty entity classes share. Then, you would be able to have each entity class implement this interface (let's call it IMyEntity) by doing something like
public partial class EntityNumber1 : IMyEntity
{
}
for each entity (where EntityNumber1 is the name of one of the entity classes). Granted, this is still thirty different definitions, but your CRUD operation class could then operate on IMyEntity instead of having to write a new class each time.
A second way to do this is simply to genericize the CRUD operation class, as you suggest:
public class ExampleAttributes<T> : IAttributeList
{
...
which allows you to use T as the type on which to operate. Granted, this might be easier in combination with the first method, since you would still have to check for the presence of the attributes and cast the entity to the appropriate type or interface.
Edit:
To check for the presence of the appropriate properties on the entity, you might need to use reflection methods. One way to check whether the given type T has a particular property might be to check for
typeof(T).GetProperties().OfType<PropertyInfo>().Count<PropertyInfo>(pi => pi.Name == "MyPropertyName" && pi.GetGetMethod().ReturnType == typeof(TypeIWant)) > 0
Of course, replace TypeIWant with the type you are expecting the property to be, and replace MyPropertyName with the name of the property for which you are checking.
Add a parameter to the constructors which specifies the type. Then you can work with it internally. One class, with perhaps a switch statement in the constructor.
For genericising a LINQ query, the biggest problem is that your DataContext has the collections based on type. There are a few ways this can be circumvented. You could try to access it using reflection, but that will require quite a bit of hacking and would pretty much destroy all efficiency that LINQ to SQL would provide.
The easiest way seems to be to use Dynamic LINQ. I have not used it personally, but it seems like it should support it. You can find more information in this thread: Generic LINQ query predicate?
and on http://aspalliance.com/1569_Dynamic_LINQ_Part_1_Using_the_LINQ_Dynamic_Query_Library.1
Maybe someone else can provide more information about this?
This isn't necessarily an answer to the question, but may be a solution to your problem. Have you considered generating all the classes that you need? T4 is built into Visual Studio, and can generate code for you. The link below describes it fairly broadly, but contains heaps of links for further information.
http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx
That way, you can define all the methods in one place, and generate the class files for your 30-odd lookup models. One place to make changes etc.
Maybe worth considering, and if not, still worth knowing about.

Merging these two very similar methods

I have these two methods on a service:
public Offer GetOffer(int id, string languageCode = Website.LanguageSettings.DefaultLanguageCode)
{
Entities.Offer offerEntity = _db.Offers.FirstOrDefault(offer => offer.Id == id);
if (languageCode.ToLower(CultureInfo.InvariantCulture) != Website.LanguageSettings.DefaultLanguageCode)
{
using (IDocumentSession session = store.OpenSession())
{
Translation.Offer translatedOffer = session.LuceneQuery<Translation.Offer>(Website.RavenDbSettings.Indexes.Offers)
.Where(string.Format("ObjectId:{0} AND LanguageCode:{1}", id, languageCode))
.OrderByDescending(offer => offer.Id)
.FirstOrDefault();
var offerPOCO = Mapper.DynamicMap<Translation.Offer, Offer>(translatedOffer);
offerPOCO.Id = offerEntity.Id;
return offerPOCO;
}
}
return Mapper.Map<Entities.Offer, Offer>(offerEntity);
}
And
public Hotel GetHotel(int id, string languageCode = Website.LanguageSettings.DefaultLanguageCode)
{
Entities.Hotel hotelEntity = _db.Hotels.FirstOrDefault(hotel => hotel.Id == id);
if (languageCode.ToLower(CultureInfo.InvariantCulture) != Website.LanguageSettings.DefaultLanguageCode)
{
using(IDocumentSession session = store.OpenSession())
{
Translation.Hotel translatedHotel = session.LuceneQuery<Translation.Hotel>(Website.RavenDbSettings.Indexes.Hotels)
.Where(string.Format("ObjectId:{0} AND LanguageCode:{1}", id, languageCode))
.OrderByDescending(hotel => hotel.Id)
.FirstOrDefault();
Hotel hotelPOCO = Mapper.DynamicMap<Translation.Hotel, Hotel>(translatedHotel);
hotelPOCO.Id = hotelEntity.Id;
return hotelPOCO;
}
}
return Mapper.Map<Entities.Hotel, Hotel>(hotelEntity);
}
They are exactly the same in most aspects: they take the same params, build the same query and make the same operations, the only thing that varies is the type of objects they work with and output. Besides building a method to generate the Where() param string, I can't think of any way I can merge most (or all) of this code into a single method and then just call it from the GetOffer() and GetHotel() methods since I'll end up with several more just like these two.
Any advice is greatly appreciated.
Edit: adding the solution so if another poor soul comes across this problem he/she can have a starting point:
private TReturn GetObject<TReturn, TEntity, TTranslation>(int id, string languageCode, string ravenDbIndex) where TEntity:EntityObject
where TTranslation:Translation.BaseTranslationObject
where TReturn:BasePOCO
{
// TODO Run more tests through the profiler
var entities = _db.CreateObjectSet<TEntity>();
var entityKey = new EntityKey(_db.DefaultContainerName + "." + entities.EntitySet.Name, "Id", id); // Sticking to the Id convention for the primary key
TEntity entity = (TEntity)_db.GetObjectByKey(entityKey);
if(languageCode.ToLower(CultureInfo.InvariantCulture) != Website.LanguageSettings.DefaultLanguageCode)
{
using(IDocumentSession session = store.OpenSession())
{
TTranslation translatedObject = session.LuceneQuery<TTranslation>(ravenDbIndex)
.Where(string.Format("ObjectId:{0} AND LanguageCode:{1}", id, languageCode))
.OrderByDescending(translation => translation.Id)
.FirstOrDefault();
TReturn poco = Mapper.DynamicMap<TTranslation, TReturn>(translatedObject);
poco.Id = id;
return poco;
}
}
return Mapper.Map<TEntity, TReturn>(entity);
}
And then I just call:
GetObject<Hotel, Entities.Hotel, Translation.Hotel>(id, languageCode, Website.RavenDbSettings.Indexes.Hotels);
Whenever I need a hotel.
Thank you all for the great replies, learned quite a lot from them.
It looks as though you could refactor this into a generic method. Something similar to this (I'm making some assumptions about the ability to refactor some method calls, etc. But hopefully you get the idea)
public T Get<T>(int id, string languageCode = Website.LanguageSettings.DefaultLanguageCode)
{
Entity<T> entity = _db<T>.FirstOrDefault(entity => entity.Id == id);
if (languageCode.ToLower(CultureInfo.InvariantCulture) != Website.LanguageSettings.DefaultLanguageCode)
{
using(IDocumentSession session = store.OpenSession())
{
Translation<T> translatedEntity = session.LuceneQuery<Translation<T>>(Website.RavenDbSettings.Indexes.Entities<T>)
.Where(string.Format("ObjectId:{0} AND LanguageCode:{1}", id, languageCode))
.OrderByDescending(entity=> entity.Id)
.FirstOrDefault();
T POCO = Mapper.DynamicMap<Translation<T>, T>(translatedEntity);
POCO.Id = entity.Id;
return POCO;
}
}
return Mapper.Map<Entities<T>, T>(Entity);
}
Suggest keeping them as-is. They return different types, and warrant different methods. My gut feeling is that it falls under Do One Thing - Single Responsibility Principle.
True that they implement the same strategies in doing their work, but I'd suggest that if you were to merge/refactor them into one would be more confusing than benefiting.
Consider the likelihood of the business logic changing. Would one be more volatile than the other? Would implementing this be same as GetFlights() and GetCarRentals()?
I realize that when making code the same, and likely copy/pasting/tweaking code between methods, you get the sense that you could reduce lines of code, and don't repeat yourself. I value both SRP and DRY equally, but in this case, I'd rather read and maintain different methods for each entity of Offer, Hotel, etc.
In cases like this I isolate the variable terms and put them in the sig, if the sig turns out too large and difficult/ugly to call then see if generics can make this simpler or if parts can be factored into their types which is what I would think to do in this case. Also having an action or a func in the sig can help if it would never be difficult to fill in at call, something where you could maybe call:
GetDalObject(db => db.Hotels.FirstOrDefault(hotel => hotel.Id == id), ...
Then you can swap it in the call between hotel or offer or etc, but in your case I don't know how much this can help since I think the sig would really become nasty, so I would look at taking the variable parts and implementing them in the Offer type and the Hotel type, which you access via an interface, and then the Offer/Hotel class is handed to this method.
public interface ICommonDalObject
{
public string LuceneQueryString { get; }
public ITranslation GetTranslation();
}

Categories