Entity Framework: When to use Set<> - c#

I'm trying understand the basics of Entity Framework and I have a question about the Set<> method on DbContext. I am using a database first model for the following question.
Let's say I have an ActivityLog database which amongst other things I can use to pull out a message (NLog message, for example). I could write some code to pull out all messages like this:
using (var entities = new ActivityLogEntities())
foreach (var log in entities.AcitivityLogs)
Console.WriteLine(log.Message);
However I could also achieve the same thing doing this:
using (var entities = new ActivityLogEntities())
foreach (var message in entities.Set<ActivityLog>().Select(entity => entity.Message))
Console.WriteLine(message);
My question is what is the difference between these two statements? When is it more appropriate to use one over the other? Or is this just a matter of personal preference?

There's no significant difference. In the first case, you have something like:
class MyContext : DbContext
{
public DbSet<AcitivityLog> AcitivityLogs { get; set; }
}
When context is being created, it looks for public DbSet<T> read/write-properties, and does this (pseudo-code):
dbSetProperty = Set<EntityType>();
But, there are cases, when you:
don't want to make public properties for all of you entity types;
don't know all of the entity types at context's design time.
In these cases Set<T> is the only way to get proper entity set.

The only reason i have ever used Set<T> is when you are acting on a type you dont know, eg a generic insert.
Heres an example from my generic repository:
public void AddOnSave(T entity)
{
ctx.Set<T>.Add(entity);
}
Using it for regular stuff just makes the code less readable IMHO

If your look at the generated DbContext class you'll see that AcitivityLogs is just a DbSet<ActivityLog>.
So they are the same same thing. It's just the typed definition of your DbSet.

Related

Difference between DbSet<T> property and Set<T>() function in EF Core?

Given this kind of context:
public class FooContext : DbContext
{
public FooContext(DbContextOptions<FooContext> opts) : base(opts)
{ }
public DbSet<Bar> Bars { get; set; }
}
I can get to a Bar in two ways:
fooContext.Bars.Add(new Bar()); // Approach 1
or
fooContext.Set<Bar>().Add(new Bar()); // Approach 2
What is the difference between the two approaches?
I've tried to answer my own question by:
Inspecting the intellisense for both (only tells me that Set<T>() also creates a DbSet<T>)
Googling for "EF Core Set vs property" but that doesn't seem to be the 'right' query
Google for DbSet<T> specifically on the docs urls but no relevant results here either it seems
Reading the intro of the DbSet<T> docs which just suggests that you can get a set through either of the two methods (not if there is or isn't a difference)
Read the Set<T>() docs which has no relevant info
But I could not find any good explanation about which of the two is used for which purpose. What is the difference? Or perhaps more importantly: where and how should I be able to find this in the docs?
They do exactly the same thing. The real question is when will you use one over the other.
You use DbSet when you know the type of entity you want to play with. You simple write the DbContext name then the entity type name and you can create, read, update or delete entries for this entity with the entity methods available. You know what you want and you know where to do it.
You use Set when you don't know the entity type you want to play with. Lets say, you wanted to build a class that does your repository functions for creating, reading, updating and deleting entries for an entity. You want this class to be reusable so that you can just pass a DbContext on it and it will use the same create, read, update and delete methods. You don't know for sure what DbContext it will be used on or what DbSet the DbContext will have. Here's when you use generics so that your class can be used by any DbContext for any DbSet.
Here's an example of a class you can use for creating any entity on any DbSet in any DbContext
public class Repository<TDbContext> where TDbContext : DbContext
{
private TDbContext _context { get; }
public Repository(TDbContext context)
{
_context = context;
}
public TEntity Create<TEntity>(TEntity entity) where TEntity : class
{
if(entity != null)
{
var dataSet = _context.Set<TEntity>();
if(entity is IEnumerable)
{
dataSet.AddRange(entity);
}
else
{
dataSet.Add(entity);
}
_context.SaveChanges();
}
return entity;
}
}
And this is how to use it.
var dbContext01 = new DbContext01();
var dbContext02 = new DbContext02();
var repository01 = new Repository<DbContext01>(dbContext01);
var repository02 = new Repository<DbContext02>(dbContext02);
repository01.Create(new EntityOnDbContext01 {
Property01A = "String",
Property01B = "String"
});
repository02.Create(new EntityOnDbContext02 {
Property02A = 12345,
Property02B = 12345
});
Here's a link if you want to know more about generics. Its super awesome.
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/
Unfortunately currently you won't find explanation in the official documentation, mainly because all these are functionally equivalent.
First, the generic methods of DbConext like Add<TEntity>, Remove<TEntity>, Attach<TEntity> etc. a fully equivalent of the corresponding DbSet<TEntity> methods (actually currently they are the implementation of the later, i.e. DbSet methods simply call the corresponding DbContext generic method). Which one you use is just a matter of taste.
Second, DbSet<TEntity> property and Set<TEntity> method are functionally equivalent, but do have some non functional differences.
The DbSet properties are populated once at the context creation, while Set method always performs a lookup, so DbSet property access should be faster than Set method (although not significant).
The important difference is actually the EF Core Including & Excluding Types convention:
By convention, types that are exposed in DbSet properties on your context are included in your model. In addition, types that are mentioned in the OnModelCreating method are also included.
So while you can keep your DbContext without exposed DbSet properties and work just with Set method, if you do so you have to tell explicitly EF Core which are your entity types by adding in OnModelCreating a call to modelBuilder.Entity<TEntity>(); for each entity type (this is what the documentation does mean by types that are mentioned in the OnModelCreating method).
They are the same and actually returns the same DbSet instance.
var options = //...;
using (var ctx = new FooContext(options))
{
// true
bool isSame = ReferenceEquals(ctx.Bars, ctx.Set<Bar>());
}
One use case for not including a DbSet property in your DbContext is when you want to hide an entity type from a consumer. (e.g. an entity that acts as join table for many-to-many relationship). You can then mark the entity as internal class so consumers also can't also access it using Set<>.
Also, if you don't expose a DbSet property, you need to explicitly configure the entity or you'll get the following exception:
//throws System.InvalidOperationException: 'The entity type 'Foo' was not found. Ensure that the entity type has been added to the model.'
ctx.Set<Foo>().Add(new Foo());

Entity Framework Code First: Is there a way to automatically filter disabled rows from DbSets?

In the data architecture I have to contend with, there are no deletes. Instead, all records have a nullable datetime2 that signals the record has been "disabled". This means that in the cases of direct selections on the entities, I'll always have to add in a check to see if the entity was disabled or not.
So far what I've come up with is just a simple extension method called .Enabled() that gets only the enabled rows. It seems effective so far, but it's also annoying that I have to type that in every case.
Surely someone else has skinned this cat before. Is there a better way to do this with Entity Framework I'm just not privy to?
I suppose you could do something like this
public class MyContext : DbContext
{
public IDbSet<Thing> Things { get; set; }
public IQueryable<Thing> EnabledThings
{
get
{
return Things.Where(t => t.Enabled);
}
}
}
or the same as an extension method (but on the context not the DbSet/queriable).
Personally in practice I actually do exactly as you have in your example and use Things.Enabled().Whatever
I don't know of anything native to Entity Framework. But normally when I run into this, I create an "repository" layer that I run most database transactions through. Then I create methods like GetAll() which returns all items with appropriate where statement in place to hide "deleted" items.

How can we do object filtering in Entity Framework?

When defining an object context, using code first in entity framework, for example:
public class DomainContext : DbContext
{
public DomainContext() { }
public virtual DbSet<News> News { get; set; }
}
We all know that you can query "News" doing something like (for example, to get all news that were published today):
var ctx = new DomainContext();
ctx.News.Where(x => x.PublishedDate == DateTime.Now.Date)
But, and this is the question: Is there a way to apply a pre-defined filtering/condition to all queries that pass through ctx.News? Say that I wanted that all queries on ctx.News to have the "Published Today" filtering implicit applied?
There is no way to add automatic condition (filter) to querying news. All posted examples work but only if you query News directly. If you for example loads navigation property pointing to News examples will fail.
EDMX solve this by conditional mapping but this leads to other very bad disadvantages. Conditional mapping is fixed (cannot be changed without rebuilding model) and you can have only single condition for each type - it is like TPH degraded to single entity type. Moreover conditions defined in conditional mapping probably cannot work with "Today". Conditional mapping is not available in code-first approach.
I don't believe there's a way to add a filter to the DbSet<News> object as you're suggesting. But what you should be able to do is just write another function:
public virtual IEnumerable<News> TodaysNews
{
get { return News.WHere(n => n.PublishDate == DateTime.Today); }
}
And then, I think, if you did a query on top of that somewhere else, like:
var todaysGoodNews = from n in ctx.TodaysNews
where n.IsGood == true
select n;
then it would combine the queries when it sent it to the server rather than making it two separate queries. I'm not positive if that works when you use IEnumerable<> or if you need to return something else (IQueryable<>, perhaps?).
Edit:
I just saw your response to the other poster below. I guess I took too long to type/format. I don't know of any way to apply a filter like that, but aren't our solutions effectively doing that? You could even make TodaysNews be the only way to directly access that object through the context or something.
You could add a new property to your context:
public IEnumerable<News> TodaysNews
{
get
{
return this.News.Where(x => x.PublishedDate == DateTime.Now.Date);
}
}
Any further filtering/sorting/etc can then be applied to the property.
Update:
If you're not able to just use a pre-filtered query, another option is to create a view in your database and map your entity to that view. The view could be based on the current date.
I'm facing the same problem and I found this: EntityFramework.Filters. This post shows how to use it.

How do I convert SQL results into a list of objects in C#?

I am working on converting a web application over to a WPF desktop application. I want to use the existing data access layer so I don't have to rewrite all the SQL queries.
But, as it stands, everything is populated almost purely from DataTables returned from SQL queries. To make things a bit easier to manage, in some instances, it would really be nice to convert these things into objects.
For example, I have a query that pulls out report information. I may get 500 results with columns like ReportID, ReportTitle, ReportDate.
I would like to make a report class that has these public attributes and somehow convert the SQL query results into a collection of these report objects.
What is the best way to go about doing this?
Super bonus points if there is an easy way of going backwards (updating the database if the objects are changed).
You should learn about Object-Relational Mapping (ORM). A good ORM can save you tonnes of work in the future, and gets those nasty queries out of your code.
I'd recommend NHibernate or Entity Framework 4.0
While I would also like to suggest ORM (NHibernate is the way to go:)) a possible solution is:
public IEnumerable<Report> ToReportList(DataTable dt)
{
return dt.AsEnumerable().Select(dr => new Report
{
member1 = dr["column1"].ToString(),
...
});
}
Report is your class here by the way.Such as,
internal class Report
{
public string member1{ get; set;}
...
}
You may also want to check this,
http://msdn.microsoft.com/en-us/library/Bb399375(v=VS.100).aspx
I think if you search stackoverflow, you will find nicer examples as I remember learning this from here.
By the way, if you use NHibernate, you won't have to rewrite your queries at all. All you have to do is map your tables to a class and booya you are good to go. It will handle all your DML stuff (well mostly) and you can easily tell the ORM to do LazyLoad, Batch processing etc which is pretty cool.
Super bonus points if there is an easy
way of going backwards (updating the
database if the objects are changed).
For that , go for ORM i.e. NHibernate (I know I am biased :)). For LINQ to SQL examples check the 2 links below:
http://msdn.microsoft.com/en-us/library/bb386931.aspx
http://csainty.blogspot.com/2008/01/linq-to-sql-insertupdatedelete.html
+1 ORM. Entity Framework is good, LINQ to SQL is good too, but you'd need a good database design and is better for pretty basic SQL CRUD actions. For custom entities from multiple datasources, I'd go EF.
As far as backwards updating - LINQ to SQL has an easy-peasy implementation, sorta like this - say you've got a db called MyDatabase with Dog entities in it:
using(MyDatabaseDataContext db = new MyDatabaseDataContext())
{
//LINQ will automatically pluralize your items (entity named Dog becomes Dogs)
Dog d = db.Dogs.Where(x=>x.DogName.Equals(dogName));
d.Owner = "Steve";
db.SubmitChanges();
//adding new items is easy too
Dog newdog = new Dog();
newDog.DogName = "Scruff";
newDog.Owner = "Jim";
db.Dogs.Add(newDog);
db.SubmitChanges();
}
Check out this method. First you can create a class that inherits DataContext. And then you can use methods of DataContext like to ExecuteQuery<> to convert your results in to objects. With this method you can directly use your queries you wrote earlier. Also, I feel that this way is a lot better than maintaining a .dbml file, because of the issues associated to synchronization with the actual database schema.
Consider the following example. First you need to define a class for interacting with your database
public class DBManagerDataContext : DataContext
{
private static string connectionString = ""; // Your connection string
public static DBManagerDataContext CreateInstance()
{
return new DBManagerDataContext(connectionString);
}
protected DBManagerDataContext(string connectionString)
: base(connectionString, new AttributeMappingSource())
{
}
}
Then you can use this context to execute queries and convert them in to objects as shown below:
public class Report
{
public int ReportID;
public string ReportTitle;
public DateTime ReportDate;
private static string query = "select ReportID, ReportTitle, ReportDate from dbo.Reports"; // Your query
public static List<Report> GetReportList()
{
DBManagerDataContext context = DBManagerDataContext.CreateInstance();
return context.ExecuteQuery<Report>(query).ToList();
}
}
You can use the method "GetReportList()" given above like this for example:
List<Report> reports = Report.GetReportList();
In the case of updates, the method suggested by "jdandison" is a nice option, apart from using the data context as above. In the case of updates it would be "ExecuteCommand" though. Please explore the DataContext class for more information.
Edit: Please note that the query column names should match the definition in the object

Problem using LINQ to SQL with one DataContext per atomic action

I have started using Linq to SQL in a (bit DDD like) system which looks (overly simplified) like this:
public class SomeEntity // Imagine this is a fully mapped linq2sql class.
{
public Guid SomeEntityId { get; set; }
public AnotherEntity Relation { get; set; }
}
public class AnotherEntity // Imagine this is a fully mapped linq2sql class.
{
public Guid AnotherEntityId { get; set; }
}
public interface IRepository<TId, TEntity>
{
Entity Get(TId id);
}
public class SomeEntityRepository : IRepository<Guid, SomeEntity>
{
public SomeEntity Get(Guid id)
{
SomeEntity someEntity = null;
using (DataContext context = new DataContext())
{
someEntity = (
from e in context.SomeEntity
where e.SomeEntityId == id
select e).SingleOrDefault<SomeEntity>();
}
return someEntity;
}
}
Now, I got a problem. When I try to use SomeEntityRepository like this
public static class Program
{
public static void Main(string[] args)
{
IRepository<Guid, SomeEntity> someEntityRepository = new SomeEntityRepository();
SomeEntity someEntity = someEntityRepository.Get(new Guid("98011F24-6A3D-4f42-8567-4BEF07117F59"));
Console.WriteLine(someEntity.SomeEntityId);
Console.WriteLine(someEntity.Relation.AnotherEntityId);
}
}
everything works nicely until the program gets to the last WriteLine, because it throws an ObjectDisposedException, because the DataContext does not exist any more.
I do see the actual problem, but how do I solve this? I guess there are several solutions, but none of those I have thought of to date would be good in my situation.
Get away from the repository pattern and using a new DataContext for each atomic part of work.
I really would not want to do this. A reason is that I do not want to be the applications to be aware of the repository. Another one is that I do not think making linq2sql stuff COM visible would be good.
Also, I think that doing context.SubmitChanges() would probably commit much more than I intended to.
Specifying DataLoadOptions to fetch related elements.
As I want my Business Logic Layer to just reply with some entities in some cases, I do not know which sub-properties they need to use.
Disabling lazy loading/delayed loading for all properties.
Not an option, because there are quite a few tables and they are heavily linked. This could cause a lot of unnecessary traffic and database load.
Some post on the internet said that using .Single() should help.
Apparently it does not ...
Is there any way to solve this misery?
BTW: We decided to use Linq t0 SQL because it is a relatively lightweight ORM solution and included with the .NET framework and Visual Studio. If the .NET Entity Framework would fit better in this pattern, it may be an option to switch to it. (We are not that far in the implementation, yet.)
Rick Strahl has a nice article about DataContext lifecycle management here: http://www.west-wind.com/weblog/posts/246222.aspx.
Basically, the atomic action approach is nice in theory but you're going to need to keep your DataContext around to be able to track changes (and fetch children) in your data objects.
See also: Multiple/single instance of Linq to SQL DataContext and LINQ to SQL - where does your DataContext live?.
You have to either:
1) Leave the context open because you haven't fully decided what data will be used yet (aka, Lazy Loading).
or 2) Pull more data on the initial load if you know you will need that other property.
Explaination of the latter: here
I'm not sure you have to abandon Repository if you go with atomic units of work. I use both, though I admit to throwing out the optimistic concurrency checks since they don't work out in layers anyway (without using a timestamp or some other required convention). What I end up with is a repository that uses a DataContext and throws it away when it's done.
This is part of an unrelated Silverlight example, but the first three parts show how I'm using a Repository pattern with a throwaway LINQ to SQL context, FWIW: http://www.dimebrain.com/2008/09/linq-wcf-silver.html
Specifying DataLoadOptions to fetch related elements. As I want my Business Logic Layer to just reply with some entities in some cases, I do not know which sub-properties they need to use.
If the caller is granted the coupling necessary to use the .Relation property, then the caller might as well specify the DataLoadOptions.
DataLoadOptions loadOptions = new DataLoadOptions();
loadOptions.LoadWith<Entity>(e => e.Relation);
SomeEntity someEntity = someEntityRepository
.Get(new Guid("98011F24-6A3D-4f42-8567-4BEF07117F59"),
loadOptions);
//
using (DataContext context = new DataContext())
{
context.LoadOptions = loadOptions;
This is what I do, and so far it's worked really well.
1) Make the DataContext a member variable in your repository. Yes, this means you're repository should now implement IDisposable and not be left open... maybe something you want to avoid having to do, but I haven't found it to be inconvenient.
2) Add some methods to your repository like this:
public SomeEntityRepository WithSomethingElseTheCallerMightNeed()
{
dlo.LoadWith<SomeEntity>(se => se.RelatedEntities);
return this; //so you can do method chaining
}
Then, your caller looks like this:
SomeEntity someEntity = someEntityRepository.WithSomethingElseTheCallerMightNeed().Get(new Guid("98011F24-6A3D-4f42-8567-4BEF07117F59"));
You just need to make sure that when your repository hits the db, it uses the data load options specified in those helper methods... in my case "dlo" is kept as a member variable, and then set right before hitting the db.

Categories