Applying Linq to a DbSet inside DbContext - c#

Suppose I have a model called Item which looks like this:
public int ID { get; set; }
public DateTime DateCreated { get; set; }
public DateTime? DateArchived { get; set; }
[Required]
public string Alias { get; set; }
It has been included in the DbContext...
public DbSet<Item> Items { get; set; }
Whenever I want to select all items from the database, I want to include only items where Archived == null and sorted by Alias.
Is there a way to set up EF to do this when the DbSet is called (eg. on the DbContext)?
For example, if I call db.Items in a controller, I always want these options applied without having to state them explicitly.
My current way to do this is to rename the DbSet with prefix "All" and add a function with these options applied (function uses DbSet's original name so that scaffold controllers and pages use the customized query without requiring any changes):
public DbSet<Item> AllItems { get; set; }
public IQueryable<Item> Items
{
get { return AllItems.Where(item => item.Archived == null).OrderBy(item => item.Alias); }
}
But something about this method feels hackish/wrong. Is this a fine way to do it? How should this typically done?

I've had similiar problem once and I created a database view to present my data with all neccessary limitations. View can have the same fields as a table, but not required to. Then you create another DbSet item, e.g. DbSet<ItemView>, which in the database coresponds to view instead of table. Inside of this view you declare where statement as you wish. If properties are the same, you can also create the same ancestor for both classes (e.g. Item and ItemView both inherit from ItemBase).
I've had this done on MS SQL Server.

I generally avoid accessing DbSet's directly and enforce the idea by hiding the context behind an interface. Then I only access repository methods from the interface. This hides the DbSets from intelli-sense when using it in your client code if you'd prefer client code doesn't have access to the table collections (and want to steer them to some filtered subset of data).
public interface IDataContext : IDisposable
{
void SaveChanges();
IQueryable<Item> GetItems();
}
public class DataContext : DbContext, IDataContext
{
public DataContext(string connectionStringName) : base(connectionStringName) { }
public DbSet<Item> Items { get; set; }
public IQueryable<Item> GetItems()
{
return Items.Where(item => item.Archived == null).OrderBy(item => item.Alias);
}
}
using (IDataContext context = new DataContext("myConnection"))
{
var items = context.GetItems();
}

Related

Pre-filtering results with entity framework database-first

Using EF database-first, is it possible to create a duplicate of one of the classes, such that any query made comes back with an additional filter?
As an example: Given a class
public partial class Person
{
public Person()
{
this.Job= new HashSet<Appointments>();
}
public int PersonID { get; set; }
public int JobID { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
public virtual ICollection<Appointments> Appointments { get; set; }
}
Is it possible to construct a duplicate of the class in some way that functions like the existing class, but will only return results applied a "where Forename = 'David')
I can't overwrite the existing class (both cases need to be kept, and it'll be overwritten anyway)
My first thought was to simply create a seperate static class with methods that return an IQueryable< Persons>, but to then call that later, the context has been disposed - I don't think you can attach it to a new context?
The best you could do would be to add a function to your DbContext, in a partial class, that returns an IQueryable<Persons> with the filter already applied.
The partial class should have the same name as your actual context class. Any code in the partial class will be merged with the Database-First generated class, as if they were in the same file. It also won't get touched or overwritten by the code-generator if you regenerate the context. You can use this same concept to extend all kinds of code-generated classes (this is exactly the kind of use-case that partial classes were designed for).
public partial class MyDbContext
{
public IQueryable<Persons> FilteredPersons()
{
return this.Persons.Where(p => p.Forename =="David");
}
}
Then you can call it like this:
using (var myContext = new MyDbContext())
{
var query = myContext.FilteredPersons().Where(...some additional filter...);
var results = query.ToList();
}
You could probably also rig something up with an IDBCommandInterceptor, but that would be huge, hacky, ugly, and beyond the scope of a simple answer like this.

Automapper creating new instance rather than map properties

This is a long one.
So, I have a model and a viewmodel that I'm updating from an AJAX request. Web API controller receives the viewmodel, which I then update the existing model using AutoMapper like below:
private User updateUser(UserViewModel entityVm)
{
User existingEntity = db.Users.Find(entityVm.Id);
db.Entry(existingEntity).Collection(x => x.UserPreferences).Load();
Mapper.Map<UserViewModel, User>(entityVm, existingEntity);
db.Entry(existingEntity).State = EntityState.Modified;
try
{
db.SaveChanges();
}
catch
{
throw new DbUpdateException();
}
return existingEntity;
}
I have automapper configured like so for the User -> UserViewModel (and back) mapping.
Mapper.CreateMap<User, UserViewModel>().ReverseMap();
(Note that explicitly setting the opposite map and omitting the ReverseMap exhibits the same behavior)
I'm having an issue with a member of the Model/ViewModel that is an ICollection of a different object:
[DataContract]
public class UserViewModel
{
...
[DataMember]
public virtual ICollection<UserPreferenceViewModel> UserPreferences { get; set; }
}
The corresponding model is like such:
public class User
{
...
public virtual ICollection<UserPreference> UserPreferences { get; set; }
}
The Problem:
Every property of the User and UserViewModel classes maps correctly, except for the ICollections of UserPreferences/UserPreferenceViewModels shown above. When these collections map from the ViewModel to the Model, rather than map properties, a new instance of a UserPreference object is created from the ViewModel, rather than update the existing object with the ViewModel properties.
Model:
public class UserPreference
{
[Key]
public int Id { get; set; }
public DateTime DateCreated { get; set; }
[ForeignKey("CreatedBy")]
public int? CreatedBy_Id { get; set; }
public User CreatedBy { get; set; }
[ForeignKey("User")]
public int User_Id { get; set; }
public User User { get; set; }
[MaxLength(50)]
public string Key { get; set; }
public string Value { get; set; }
}
And the corresponding ViewModel
public class UserPreferenceViewModel
{
[DataMember]
public int Id { get; set; }
[DataMember]
[MaxLength(50)]
public string Key { get; set; }
[DataMember]
public string Value { get; set; }
}
And automapper configuration:
Mapper.CreateMap<UserPreference, UserPreferenceViewModel>().ReverseMap();
//also tried explicitly stating map with ignore attributes like so(to no avail):
Mapper.CreateMap<UserPreferenceViewModel, UserPreference>().ForMember(dest => dest.DateCreated, opts => opts.Ignore());
When mapping a UserViewModel entity to a User, the ICollection of UserPreferenceViewModels is also mapped the User's ICollection of UserPreferences, as it should.
However, when this occurs, the individual UserPreference object's properties such as "DateCreated", "CreatedBy_Id", and "User_Id" get nulled as if a new object is created rather than the individual properties being copied.
This is further shown as evidence as when mapping a UserViewModel that has only 1 UserPreference object in the collection, when inspecting the DbContext, there are two local UserPreference objects after the map statement. One that appears to be a new object created from the ViewModel, and one that is the original from the existing model.
How can I make automapper update an existing Model's collection;s members, rather than instantiate new members from the ViewModel's collection? What am I doing wrong here?
Screenshots to demonstrate before/after Mapper.Map()
This is a limitation of AutoMapper as far as I'm aware. It's helpful to keep in mind that while the library is popularly used to map to/from view models and entities, it's a generic library for mapping any class to any other class, and as such, doesn't take into account all the eccentricities of an ORM like Entity Framework.
So, here's the explanation of what's happening. When you map a collection to another collection with AutoMapper, you are literally mapping the collection, not the values from the items in that collection to items in a similar collection. In retrospect, this makes sense because AutoMapper has no reliable and independent way to ascertain how it should line up one individual item in a collection to another: by id? which property is the id? maybe the names should match?
So, what's happening is that the original collection on your entity is entirely replaced with a brand new collection composed of brand new item instances. In many situations, this wouldn't be a problem, but when you combine that with the change tracking in Entity Framework, you've now signaled that the entire original collection should be removed and replaced with a brand new set of entities. Obviously, that's not what you want.
So, how to solve this? Well, unfortunately, it's a bit of a pain. The first step is to tell AutoMapper to ignore the collection completely when mapping:
Mapper.CreateMap<User, UserViewModel>();
Mapper.CreateMap<UserViewModel, User>()
.ForMember(dest => dest.UserPreferences, opts => opts.Ignore());
Notice that I broke this up into two maps. You don't need to ignore the collection when mapping to your view model. That won't cause any problems because EF isn't tracking that. It only matters when you're mapping back to your entity class.
But, now you're not mapping that collection at all, so how do you get the values back on to the items? Unfortunately, it's a manual process:
foreach (var pref in model.UserPreferences)
{
var existingPref = user.UserPreferences.SingleOrDefault(m => m.Id == pref.Id);
if (existingPref == null) // new item
{
user.UserPreferences.Add(Mapper.Map<UserPreference>(pref));
}
else // existing item
{
Mapper.Map(pref, existingPref);
}
}
In the meantime there exists an AutoMapper Extension for that particular problem:
cfg.AddCollectionMappers();
cfg.CreateMap<S, D>().EqualityComparison((s, d) => s.ID == d.ID);
With AutoMapper.EF6/EFCore you can also auto generate all equality comparisons. Plaese see AutoMapper.Collection AutoMapper.EF6 or AutoMapper.Collection.EFCore
According to the AutoMapper source file that handles all ICollection (among other things) and the ICollection Mapper:
The collection is cleared by a call to Clear() then added again, so as far as I can see there is no way that AutoMapper will be able to automagically do the mapping this time.
I would implement some logic to loop over the collections and AutoMapper.Map the ones that are the same

DbContext - Best Practice for Saving Child Collections when Working with Disconnected Entities

I'm attempting to separate my DbContext from a winforms application that I'm currently using to better support a multi-user environment as well as an upcoming website. After doing a bit of research I've going with implementing a data access layer (DAL) for the winforms app/website to connect to and having the end-users work with disconnected entities. My question is regarding the best way I would go about saving updates to my entities when one of the entities in a child collection has been updated.
For instance, if I have the following structure (simplified)
public class Company
{
public int CompanyID { get; set; }
public string CompanyName { get; set; }
public ICollection<Employee> Employees { get; set; } // Non-virtual as we aren't lazy-loading
}
public class Employee
{
public int CompanyID { get; set; }
public int EmployeeID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public ICollection<Claim> Claims { get; set; }
}
public class Claim
{
public DateTime ClaimDate { get; set; }
public ICollection Documentation { get; set; }
}
public class Document
{
public byte[] DocumentImage { get; set; }
public string Name { get; set; }
public DateTime CreateDate { get; set; }
}
Inside the winforms application, I have multiple Binding Source's set-up to display the employee's information
For Example:
employeeBinding.DataSource = typeof(Employee); // Eventually set to an IEnumerable<Employee>
claimBinding.DataSource = employeeBinding;
claimBinding.DataMember = "Claims";
documentationBinding.DataSource = claimBinding;
documentationBinding.DataMember = "Documentation";
However, by setting things up like this I'm unable to make calls on the "CurrentChanged" event of each binding source to save each entity since it has changed (unless I have references stored to the previous entity inside the form). So what I have thought to do was something similar to below in the DAL and iterate through each of the child collections.
public void UpdateEmployee(Employee employee)
{
using (myContext context = new myContext())
{
context.Employees.Attach(employee);
context.Entry<Employee>(employee).State = EntityState.Modified;
foreach(var claim in employee.Claims)
{
context.Entry<Claim>(claim).State = EntityState.Modified;
foreach(var doc in claim.Documentation)
{
context.Entry<Document>(doc).State = EntityState.Modified;
}
}
context.SaveChanges();
}
}
However, I feel that this route can get ugly quick with some more complex entities and relationships. Could someone help point me to the best route to handle this or should I have references to the current entities in the code so when the "CurrentChanged" event fires I can just update each individual entity?
Thank you very much.
When you work with Entity Framework you have the ChangeTracker, even if you are using this "Disconected entities" you can have the ChangeTracker tracking the entities, to have this you just need to attach them to the context and before you call the SaveChanges you call .DetectCHanges() You dont really need to have this specific code, you can use generics for this:
public void Update<TEntity>(TEntity entity)
{
using (myContext context = new myContext())
{
context.Set<TEntity>.Attach(entity);
context.ChangeTracker.DetectChanges();
context.SaveChanges();
}
}
the call to the method would be:
Update<Employee>(employees);
Also i think is better for you to use a BindingSouce as the DataSource, and set the DataSource of the BindingSource as a List instead of typeof(Employee)
I could be wrong but I don't believe DetectChanges will be able to determine that there have been changes made to a disconnected entity. When the entity is attached, it will have an EntityState of "Unchanged" so wouldn't the DbContext do nothing with it until you mark it's state as "Modified". Also, as indicated in the following URL, "DetectChanges" is called for a number of methods (including "Attach") anyways and the explicit call would not be needed.
http://msdn.microsoft.com/en-us/data/jj556205.aspx
As for the BindingSource, I was illustrating that that BindingSource will be set to typeof(Employee) as if I was setting up my code in the constructor before the load events where I would actually get my data and set it's datasource to an IEnumerable from the DAL call. If I didn't do this, I would run into issues when attempting to bind to the "DataMember" properties as the other BindingSources wouldn't be able to find the properties indicated.
I don't believe that the code you provided as a sample fixes the issue I'm running into regarding child collections being updated. When testing with LinqPad they'll be updated if the parent entity has changed as well, but not if there have been zero changes to the parent. That's why I was iterating through all child collections and marking them as "Modified".

How can I add default values to a property when saving using Code First EF4.1?

I started by creating some models like this:
public abstract class EditableBase
{
public DateTime CreatedOn { get; set; }
public DateTime ModifiedOn { get; set; }
public int CreatedBy { get; set; }
public int ModifiedBy { get; set; }
}
public class Project : EditableBase
{
public int ProjectId { get; set; }
public string ProjectName { get; set; }
}
And I use this line when the app starts:
Database.SetInitializer<ModelContext>(
new DropCreateDatabaseIfModelChanges<ModelContext>());
A table called Projects is created with all the properties mentioned above as columns... this is exactly what I wanted.
However, now I need populate some default values when I issue a SaveChanges() on DbContext. When I save I need to update the ModifiedOn and ModifiedBy properties with the appropriate values.
Normally I would at least do the DateTime values on the database side (either a trigger or a stored procedure) however this is obviously not an option here since the database will be dropped anytime a class changes. And since I did code first I do not have a model designer that I can tweak the properties on.
What I would like to do is add a method in the EditableBase class that gets called when the SaveChanges() is executed, thus keeping all the logic involved in one place. Is it possible to do this? What is the best way to achieve my goal?
Override SaveChanges in your derived DbContext:
public override int SaveChanges()
{
foreach(var entry in ChangeTracker.Entries<EditableBase>())
{
var entity = entry.Entity;
if (entry.State == EntityState.Added)
{
entity.CreatedOn = ...;
entity.CreatedBy = ...;
}
else if (entry.State == EntityState.Modified)
{
entity.ModifiedOn = ...;
entity.ModifiedBy = ...;
}
}
return base.SaveChanges();
}
I'm only not sure if generic Entries will work directly with your base type becasue it is not actually mapped as base entity. There is also non generic version so you can rewrite it to more complex linq query or test each entry's entity type in loop.
Well, you have complete control over the code for your entities. I'd imagine you would probably want to implement an IPropertyChanged like pattern to update your properties.
Did consider the two options in this post where you do something on the setter (or constructor)?
The default attribute solution seems a good one.

How to load entities into private collections using the entity framework

I have a POCO domain model which is wired up to the entity framework using the new ObjectContext class.
public class Product
{
private ICollection<Photo> _photos;
public Product()
{
_photos = new Collection<Photo>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual IEnumerable<Photo> Photos
{
get
{
return _photos;
}
}
public void AddPhoto(Photo photo)
{
//Some biz logic
//...
_photos.Add(photo);
}
}
In the above example i have set the Photos collection type to IEnumerable as this will make it read only. The only way to add/remove photos is through the public methods.
The problem with this is that the Entity Framework cannot load the Photo entities into the IEnumerable collection as it's not of type ICollection.
By changing the type to ICollection will allow callers to call the Add mentod on the collection itself which is not good.
What are my options?
Edit:
I could refactor the code so it does not expose a public property for Photos:
public class Product
{
public Product()
{
Photos = new Collection<Photo>();
}
public int Id { get; set; }
public string Name { get; set; }
private Collection<Photo> Photos {get; set; }
public IEnumerable<Photo> GetPhotos()
{
return Photos;
}
public void AddPhoto(Photo photo)
{
//Some biz logic
//...
Photos.Add(photo);
}
}
And use the GetPhotos() to return the collection. The other problem with the approach is that I will loose the change tracking abilities as I cannot mark the collection as Virtual - It is not possible to mark a property as private virtual.
In NHibernate I believe it's possible to map the proxy class to the private collection via configuration. I hope that this will become a feature of EF4. Currently i don't like the inability to have any control over the collection!
The way to do this is to have a protected virtual property which is mapped in your model and a public property that returns an IEnumerable.
public class Product
{
public Product()
{
PhotoCollection = new Collcation<Photo>();
}
public int Id { get; set; }
public string Name { get; set; }
protected virtual ICollection<Photo> PhotoCollection {get; set; }
public IEnumerable<Photo> Photos
{
get { return PhotoCollection ; }
}
public void AddPhoto(Photo photo)
{
//Some biz logic
//...
PhotoCollection .Add(photo);
}
}
Anton, it would help me understand your problem more if you can explain why is it that you do not want developers to access the Add method of your collection. Is this because the list is strictly read-only, or is it because you want to run some custom business logic when a new entity is added?
Anyway... I am going to assume that you are trying to do the latter (i.e. run custom business logic when the collection is modified). I have done a similar solution on a project of mine, and the idea is as follows:
The TT template that produces POCOs in EF4 creates all collections as TrackableCollection lists. This class has an event called 'CollectionChanged' which you can subscribe to and listen to any changes to your collection.
So you can do something as follows:
public class Product
{
public Product()
{
Photos.CollectionChanged += ListCollectionChanged;
}
public int Id { get; set; }
public string Name { get; set; }
public TrackableCollection<Photo> Photos
{
get
{
// default code generated by EF4 TT
}
set
{
// default code generated by EF4 TT
}
}
private void ListCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (e.Action)
{
// A new item has been added to collection
case NotifyCollectionChangedAction.Add:
{
T newItem = (T) e.NewItems[0];
// Run custom business logic
}
break;
// An existing item has been removed
case NotifyCollectionChangedAction.Remove:
{
T oldItem = (T) e.OldItems[0];
// Run custom business logic
}
break;
}
}
}
The nice thing about the above solution is that you still use your Product entity in an 'EF' manner... were any developer in your team can simply access a property of the entity directory and need run an explicit hard typed function.
Bit late to the party but this is what Observable objects are for. Allow the data structure to do what it does best. Use ObservableCollection as your field type if you don't want to build your own collection that does what you need and expose the regular ICollection type from your property. You can run any logic in the parent entity you need when the related entities in the collection change via the CollectionChanged event. If you need to selectively enable or disable modifications it's easy enough to extend an existing collection type or write a proxy collection that allows a call to a method to toggle the mutability of the collection (ISupportInitialize can be used to good effect for representing this ability BTW).
(Apologies for my initial post brevity - I was answering from my phone)
You can construct your collection through a LINQ query over an EF entity set. However, you keep the resulting collection as internal data member to your business class and expose the IEnumerable<Photo> returned by calling AsEnumerable() on the entity set as a result of the public photo.
You could cache the IEnumerable<Photos> internally as well, so that you don't call AsEnumerable() every time your caller asks for the collection. Of course, that means that if the user needs to update the collection through your public methods, you might have to refresh the cached IEnumerable. This might pose small issue if the caller has also cached the pointer to the previous IEnumerable.
Alternatively, if your caller will always work with the full entity set, the EntitySet class (of which all your EF sets will inherit) implements IEnumerable<TEntity>, so you can directly return the entity set to your caller.
Note that if you want the loading of the collection from an EF entity set to happen outside of the scope of your business class, you can make a constructor on your class that takes an ICollection. This way, once you create your object, the collection is sealed in it, and exposed only as an IEnumerable.
Why not try the following and leave use properties?
private ICollection<Photo> photos{get; set;}
public IEnumerable<Photo> Photos
{
get {return (IEnumberable<Photo>)photos;}
}
Alternatively you could use the decorator pattern to encapsulate the class into one which the collection can't be directly modified.

Categories

Resources