LINQ "include" missing. after reading this post:
http://romiller.com/2010/07/14/ef-ctp4-tips-tricks-include-with-lambda/
i would like to use include.
this is my class:
public class Service
{
#region Properties
/// <summary>
/// Gets or sets CatalogRootNodeId.
/// </summary>
public virtual int CatalogRootNodeId { get; set; }
/// <summary>
/// Gets or sets ServiceDomain.
/// </summary>
public virtual ICollection<ServiceDomain> ServiceDomain { get; set; }
#endregion
}
I would like to "Include" all ServiceDomains but "Include" option is not there
??
I'm working with MVC3 and EF.
thanks
Are you using CTP5 or CTP4?
If you do, you can use the extension method from System.Data.Entity.DbExtensions.Include.
public static IQueryable<T> Include<T>(this IQueryable<T> source, Expression<Func<T, object>> path)
var db = new MyDbContext();
var services = db.Services.Where(s => s.CatalogRootNodeId == 1).Include(s => s.ServiceDomain);
You need to call Include() on the ObjectSet<Service> from the DataContext.
Related
Because I'm supporting soft deletes in my database, I've chosen to sub-type my Thing entity as ActiveThing and DeletedThing...
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// TPH (table-per-hierarchy):
modelBuilder.Entity<MyCorp.Biz.CoolApp.Thing>()
.Map<MyCorp.Biz.CoolApp.ActiveThing>(thg => thg.Requires("Discriminator").HasValue("A"))
.Map<MyCorp.Biz.CoolApp.DeletedThing>(thg => thg.Requires("Discriminator").HasValue("D"));
}
Now, my OData endpoint (which formerly exposed Thing).. how do I get it to now only expose ActiveThings?
I think I figured it out..
Formerly, my dbContext model looked like this, only exposing my base class:
public class myDbModel:DbContext
{
public myDbModel(): base("name=ThingDb"){}
public DbSet<Thing> Things { get; set; } //db table + ThingsController source
}
Now, I've added add'l DbSets to expose my subtypes.. like this:
public class myDbModel:DbContext
{
public myDbModel(): base("name=ThingDb"){}
public DbSet<Thing> Things { get; set; } //db table
public DbSet<ActiveThing> ActiveThings { get; set; } // now my ThingsController 'GetThings' pulls from this
public DbSet<DeletedThing> DeletedThings { get; set; }
}
Here's my updated ThingsController.cs
public class ThingsController : ODataController
{
private myDbModel db = new myDbModel();
/// <summary>
/// Only exposes ActiveThings (not DeletedThings)
/// </summary>
/// <returns></returns>
[EnableQuery]
public IQueryable<Thing> GetThings()
{
return db.ActiveThings;
}
}
I am working on upgrading a WPF application from using .Net4/EF 4.4 to .Net4.5/EF 6.1. After the upgrade I will use DbContext (since there was no POCO-generator for ObjectContext).
The application use a Repository/UnitOfWork-pattern to access Entity Framework, and before the upgrade I could set the ObjectSet.MergeOption to OverwriteChanges (in the repository-class), but the DbSet-class does not have this feature. However, I know that I can get to a ObjectSet from the DbContext by using the IObjectContextAdapter. (See code below). But it seems that setting the MergeOption on the created ObjectSet will not reflect back to the DbSet.
So my question is this: is there any way to convert the ObjectSet back to a DbSet (conserving the MergeOption-setting)?
This is some of the repository class:
public class SqlRepository<T> : IRepository<T> where T : class, IEntity
{
protected DbSet<T> dbSet;
public SqlRepository(DbContext context)
{
var objectContext = ((IObjectContextAdapter)context).ObjectContext;
var set = objectContext.CreateObjectSet<T>();
set.MergeOption = MergeOption.OverwriteChanges;
dbSet = context.Set<T>();
//I would like to do something like this: dbSet = (DbSet)set;
}
}
Although not a direct answer to your question, I have come up with a T4 based solution to the EF oversight around MergeOption not being accessible in DbSet. It seems from your question this is what you are looking for?
In the default Context you have something generated by the T4 generator like:
public virtual DbSet<Person> Persons { get; set; }
public virtual DbSet<Address> Addresses { get; set; }
etc.
My approach is to edit the T4 to add Getters for each Entity that provide direct access the ObjectSet as an IQueryable:
public IQueryable<Person> GetPersons(MergeOption mergeOption = MergeOption.AppendOnly, bool useQueryImplentation = true)
{
return useQueryImplementation ? GetSet<Person>(mergeOption).QueryImplementation() : GetSet<Person>(mergeOption);
}
Then in a base DataContext
public class DataContextBase
{
/// <summary>
/// Gets or sets the forced MergeOption. When this is set all queries
/// generated using GetObjectSet will use this value
/// </summary>
public MergeOption? MergeOption { get; set; }
/// <summary>
/// Gets an ObjectSet of type T optionally providing a MergeOption.
/// <remarks>Warning: if a DataContext.MergeOption is specified it will take precedence over the passed value</remarks>
/// </summary>
/// <typeparam name="TEntity">ObjectSet entity Type</typeparam>
/// <param name="mergeOption">The MergeOption for the query (overriden by DataContext.MergeOption)</param>
protected IQueryable<TEntity> GetObjectSet<TEntity>(MergeOption? mergeOption = null) where TEntity : class
{
var set = Context.CreateObjectSet<TEntity>();
set.MergeOption = MergeOption ?? mergeOption ?? MergeOption.AppendOnly;
return set;
}
By creating a default Extension method for an IQueryable as below you can optionally add your own implenations of QueryImplementation for each table/type so that all users of your table get sorting or includes etc. (this part is not required to answer the question but its useful anyway)
So for example you could add the following to always Include Addresses when calling GetPersons()
public static class CustomQueryImplentations
{
public static IQueryable<Person> QueryImplementation(this IQueryable<Person> source)
{
return source
.Include(r => r.Addresses)
.OrderByDescending(c => c.Name);
}
}
Finally:
//just load a simple list with no tracking (Fast!)
var people = Database.GetPersons(MergeOption.NoTracking);
//user wants to edit Person so now need Attached Tracked Person (Slow)
var peson = Database.GetPersons(MergeOption.OverwriteChanges).FirstOrDefault(p => p.PersonID = 1);
//user makes changes and on another machine sometime later user clicks refresh
var people = Database.GetPersons(MergeOption.OverwriteChanges);
Or you can (as I have) write something like
Database.MergeOption = MergeOption.OverwriteChanges;
refresh loads of entities using existing Get methods but will now ALL overwrite Attached entities
Database.MergeOption = null;
Something to note is that if you load AsNoTracking before you make changes you need to either Re-Attach or probably better reload with OverwriteChanges to ensure you have the latest Entity.
I am using Julie Lerman's EF Repository techniques.
All my entities implement the following interface
public interface IEntity
{
EntityState State { get; set; }
}
All my repositories call the following GetList function
public virtual IList<T> GetList(Func<T, bool> where, params Expression<Func<T, object>>[] navigationProperties)
{
List<T> list;
IQueryable<T> dbQuery = ((DbContext)context).Set<T>();
//Apply eager loading
foreach (var navigationProperty in navigationProperties)
{
dbQuery = dbQuery.Include(navigationProperty);
}
list = dbQuery.AsNoTracking().Where(where).ToList();
return list;
}
I am finding that the initial state property for my entities is zero, but I want to set it to
I want to set State property to be EntityState.Unchanged
How should I do this?
Julie Lerman described it in her book Programming Entity Framework: DbContext At page 93
(Example 4-15).
You can use following code in your DbContext constractor to set the object states to UnChanged:
public YourContext()
{
((IObjectContextAdapter)this).ObjectContext .ObjectMaterialized +=
(sender, args) =>
{
var entity = args.Entity as IEntity;
if (entity != null)
{
entity.State = State.Unchanged;
}
}
}
Here's another easier approach to this issue. I am using it and it works!!
public abstract class Entity<TId> : BaseEntity, IEntity<TId>, IModelState
{
public virtual TId Id { get; private set; }
public byte[] RowVersion { get; protected set; }
private readonly IDictionary<Type, IEvent> events = new Dictionary<Type, IEvent>();
public IEnumerable<IEvent> Events => events.Values;
public ModelState ModelState { get; protected set; } = ModelState.Unchanged;
protected Entity()
{
ModelState = ModelState.Added;
}
... removed for brevity
make sure you're using C# 7 and Roslyn Compiler with your .NET 4.6.x
I think this is safer because only your own Entity Object will have the power to set it to unchanged when it gets initialized by EF. In my opinion DbContext should not have the right to set the "state" property of any entity.
I am moving from CodeFirst to DatabaseFirst to map my views. In my CodeFirst approach I had a base entity like this:
public abstract class BaseEntity
{
/// <summary>
/// Gets or sets the entity identifier
/// </summary>
public virtual int Id { get; set; }
... // Some more methods here for equality checking
}
I derived all my classes from this base class, since every one of them would have an Id. So I used this BaseClass to create a generic repository. My repository looks like this:
public partial class EfRepository<T> where T : BaseEntity
{
public readonly DemirbasContext context;
private DbSet<T> _entities;
/// <summary>
/// Ctor
/// </summary>
/// <param name="context">Object context</param>
public EfRepository(DemirbasContext context)
{
this.context = context;
}
public T GetById(object id)
{
return this.Entities.Find(id);
}
public void Insert(T entity)
{
try
{
if (entity == null)
throw new ArgumentNullException("entity");
this.Entities.Add(entity);
this.context.SaveChanges();
}
catch (Exception e)
{
...
}
}
// Other methods here Update, Delete etc
So I was able to create repositories just by specifying the generic type paremeter like this
EfRepository<Car> carRepo = new EfRepository<Car>();
In DatabaseFirst, I cannot derive the entity classes from a base class. Is there a way to do it or what would be your suggestions?
Oops, I missed code generators.
Right click on your data model (.EDM file) and click Add Code Generation Item. Choose DbContext (for simplified DbContext API).
This creates two files with .tt extensions: One for context and one for entities. If you expand the file, you will see .tt file holds all your classes there.
You can modify it as you need.
I have the following context:
public class DataContext : DbContext
{
/// <summary>
/// Gets or sets Addresses.
/// </summary>
public DbSet<Address> Addresses { get; set; }
/// <summary>
/// Gets or sets Users.
/// </summary>
public DbSet<Users> Users { get; set; }
}
I my application user may change data in say user data and then he may want to cancel changes. The best way to do this, is to refresh the DataContext from the database. But DbContext has no Refresh method. How can I refresh my DataContext?
You can reload the entity from the database as follows.
context.Entry(user).Reload();
Or you can try out the methods described in this question.