I am using the fake DbContext recommended by Microsoft for unit testing with EF5.
Everything is working fine, however I am using a "code first" approach, and some of the code under test is relying on lazy loading of related entities.
public partial class Entity
{
public int EntityId { get; set; }
public string EntityName { get; set; }
public virtual ICollection<EntityLifeCycle> EntityLifeCycles { get; set; }
public virtual EntityStatus PreviousStatus { get; set; }
public virtual EntityStatus CurrentStatus { get; set; }
}
Sample of usage:
if (entity.EntityLifeCycles.Count() > 0)
{
...
}
How can I modify my test code (and not the code being tested) to accommodate this?
Researched links for reference:
Testing With a Fake DbContext
Mocking your Entity Framework data context and testing it in .NET MVC
Related
Is this the correct way I can get linked tables using where or is there another way to return the data.
GetMethod
public IEnumerable<Model.MeetingPollingQuestion> GetMeetingPollingQuestion(int MeetingPollingId)
{
using (var db = new NccnEcommerceEntities())
{
using (DbContextTransaction dbTran = db.Database.BeginTransaction())
{
var ListOfMeetingPollingQuestions = (from mpq in db.MeetingPollingQuestions
where (mpq.MeetingPollingId == MeetingPollingId)
select new Model.MeetingPollingQuestion
{
MeetingPollingId = mpq.MeetingPollingId.Value,
MeetingPollingQuestionType = mpq.MeetingPollingQuestionType,
MeetingPollingParts = (from mp in db.MeetingPollingParts
where mp.MeetingPollingPartsId == mpq.MeetingPollingId
select new Model.MeetingPollingParts
{
Type= mp.Type
}).ToList(),
}).ToList();
return ListOfMeetingPollingQuestions;
}
}
}
EF Model
namespace Repository.EFModel
{
using System;
using System.Collections.Generic;
public partial class MeetingPolling
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public MeetingPolling()
{
this.MeetingPollingQuestions = new HashSet<MeetingPollingQuestion>();
}
public int MeetingPollingId { get; set; }
public Nullable<int> MeetingId { get; set; }
public Nullable<System.DateTime> StartDate { get; set; }
public Nullable<System.DateTime> EndDate { get; set; }
public string PollingTitle { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<MeetingPollingQuestion> MeetingPollingQuestions { get; set; }
}
}
namespace Repository.EFModel
{
using System;
using System.Collections.Generic;
public partial class MeetingPollingQuestion
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public MeetingPollingQuestion()
{
this.MeetingPollingParts = new HashSet<MeetingPollingPart>();
}
public int MeetingPollingQuestionId { get; set; }
public string MeetingPollingQuestionType { get; set; }
public Nullable<int> MeetingPollingId { get; set; }
public Nullable<int> SequenceOrder { get; set; }
public virtual MeetingPolling MeetingPolling { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<MeetingPollingPart> MeetingPollingParts { get; set; }
}
}
namespace Repository.EFModel
{
using System;
using System.Collections.Generic;
public partial class MeetingPollingPart
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public MeetingPollingPart()
{
this.MeetingPollingPartsValues = new HashSet<MeetingPollingPartsValue>();
}
public int MeetingPollingPartsId { get; set; }
public string Type { get; set; }
public Nullable<int> MeetingPollingQuestionId { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<MeetingPollingPartsValue> MeetingPollingPartsValues { get; set; }
public virtual MeetingPollingQuestion MeetingPollingQuestion { get; set; }
}
}
Your entities have navigation properties for the related entities, so if you want to return entities and their relatives, just eager load the related entities using Include.
public IEnumerable<Model.MeetingPollingQuestion> GetMeetingPollingQuestion(int MeetingPollingId)
{
using (var db = new NccnEcommerceEntities())
{
var questions = db.MeetingPollingQuestions
.AsNoTracking()
.Include(mpq => mpq.MeetingPollingType)
.Include(mpq => mpq.MeetingPollingParts)
.Where(mpq => mpq.MeetingPollingId == MeetingPollingId)
.ToList();
return questions;
}
}
... and that's it. The important details here is the use of Include to eager load related data, and the use of AsNoTracking to ensure that the loaded entities are not tracked by the DbContext. These will be detached entities, copies of the data but otherwise not tracking changes or an association with a DbContext. These are suitable for read-only access to the data they contain.
Whenever returning "entities" outside of the scope of a DbContext you should ensure that they are non-tracked or detached. This is to avoid errors that can come up with potential lazy load scenarios complaining about that an associated DbContext has been disposed, or errors about references being tracked by another DbContext if you try associating these entities to a new DbContext. Your code performing a Select with a new class instance does the same thing, just more code.
Personally I do not recommend working with detached entities such as ever returning entities outside of the scope of the DbContext that they were read from. Especially if you decide you only need a subset of data that the entity ultimately can provide. Entities reflect the data state, and should always be considered as Complete, or Complete-able. (i.e. Lazy loading enabled) If the code base has some code that works with tracked entities within the scope of a DbContext, vs. detached entities, vs. copies of entity classes that might be partially filled or deserialized, it makes for buggy, unreliable, and un-reusable code. Take a utility method that accepts a MeetingPollingQuestion as a parameter. As far as that method is concerned it should always get a complete MeetingPollingQuestion. The behaviour of this method could change depending on whether it was given a tracked vs. detached, vs. partially filled in copy of a MeetingPollingQuestion class. Methods like this would need to inspect the entity being passed in, and how reliable can that logic be for determining why a related entity/collection might be missing or #null?
If you need to pass entity data outside the scope of the DbContext where you cannot count on that data being complete or related data being lazy loaded as a last resort, then I recommend using POCO DTOs or ViewModels for those detached or partial representations of the data state. With a separate POCO (Populated by Select or Automapper) there is no confusion between that representation and a tracked Entity.
I am using EF Core in my Blazor Server project. I have an entity called Lesson. A Lesson can have one or more prerequisite Lessons that must be completed before it is accessible.
I would prefer to use data annotations to accomplish setting up this relationship if possible.
Is the (redacted) approach below correct?
public class Lesson : EntityBase
{
public List<LessonPrerequisiteLesson> PrerequisiteLessons { get; set; }
}
public class LessonPrerequisiteLesson : EntityBase
{
public int LessonID { get; set; }
public int PrerequisiteLessonID { get; set; }
[ForeignKey("PrerequisiteLessonID")]
[InverseProperty("PrerequisiteLessons")]
public Lesson PrerequisiteLesson { get; set; }
}
I work on a EF Core project for WPF app.
We decide to split the DbContext in 2 smaller Dbcontexts: (the project contains a single Database)
public class FirstDbContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
public DBSet<Parameters>{ get; set; }
}
public class SecondDbContext: DbContext
{
public DBSet<User>{ get; set; }
public DBSet<Books> { get; set; }
public DBSet<Parameters>{ get; set; }
}
and we keep a "super" DbContext (which contains all the DbSets from the DB) to maintain and migrate the DB
public class SuperDbContext : DbContext
{
public DbSet<Blog> Blogs { get; set; }
public DbSet<Post> Posts { get; set; }
public DBSet<User>{ get; set; }
public DBSet<Books> { get; set; }
public DBSet<Parameters>{ get; set; }
}....
The first step to refactor code is to replace the lines which references the "SuperDbContext..." with the correct call "SecondDbContext.Books..."or "FirstDbContext.Post"... OK
Question:
In the Client app, the choice of DbContext is depending about a user's choice when app is launching: if user choose option1 => FirstDbContext, and if option2 => SecondDbContext.
How can we write the code to switch on the current DbContext to manage the "common DbSet" (Parameters) : before refactoring we have for example:
SuperDbContext.Parameters.FirstOrDefault()...
and now? do we have to write something like this:
if(option1)
{
FirstDbContext.Parameters.First()
}else
{
SecondDbContext.Parameters.First()
}
And what is the impact in the repositories? cause if we maintain this approach we have to duplicate code in the 2 Repositories?
No no... Forget about the approach you mentioned, you'll end up writing twice the code you need. Why don't you just use db context type :
At the beginning of your function, a single if else :
DbContext context;
if(option1)
{
context = new firstContextEntities();
}
else
{
context = new secondContextEntities();
}
And as both of your contexts are almost exactly the same, you will use your context by casting it to the greater one (the one that has the most access) :
var FirstLine = ((secondContextEntities)context).Parameters.First();
I have a MVC4 Web api project under visual studio 2012 for which I would like to create and manage database using EF 6.0.2 code first. Actually, the solution entails four projects, namely,
OnlineShop.Application (User interface)
OnlineShop.Model dedicated to POCO classes only
OnlineShop.Test for unit tests and
OnlineShop.Core having UnitOfWork, GenericRepository and
DatabaseContext classes
Each of the mentioned projects includes an app.config which holds Same connection as that of web.config.
Problem: After running the project (in debug mode), the database is created as it's shown on server explorer (in visual studio 2012). But, it has no tables!!!
The database context class is also as the following:
public class DatabaseContext : DbContext
{
public DatabaseContext() : base("OnlineShopDb")
{
Database.SetInitializer(new MigrateDatabaseToLatestVersion<DatabaseContext, Configuration>());
}
//public static void InitializeDatabase()
//{
// using (var context = new DatabaseContext())
// {
// context.Database.CreateIfNotExists();
// Database.SetInitializer(new MigrateDatabaseToLatestVersion<DatabaseContext, Configuration>());
// }
//}
public DbSet<Person> Persons { get; set; }
public DbSet<Customer> Customers { get; set; }
public DbSet<User> Users { get; set; }
public DbSet<Audit> Audits { get; set; }
public DbSet<RoleGroup> RoleGroups { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<UserInRole> UserInRoles { get; set; }
public DbSet<Order> Orders { get; set; }
public DbSet<OrderDetail> OrderDetails { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<ProductCategory> ProductCategories { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
modelBuilder.Entity<Person>().Map<User>(c => c.Requires("Discriminator").HasValue("User"));
}
}
I have surfed the web so much, found lots of articles ans samples regarding EF code first approach but unfortunately couldn't handle this bad problem!
I would appreciate it if anyone could help me on this.
Entity Framework code first does not create your database until you try to access it, so run your project and try to get or insert some record to your database.
another usefull tip is that if you change your models EF by default will throw an exeption, and you will have to drop the current database so EF can crate a new one.
or I recomend you to change that default behavior this way
I have a problem with "Add-Migration" instruction when the Table definition is in a new DbContext Class.
I created a new ASP.NET MVC 4 Application in Visual Studio 2012.
I ran the "Enable-Migrations", "Add-Migration mig1", "Update-Database". Everything was smooth.
Than, I added a new class inheriting the DbContext to the Models folder. I was hoping that "Add-Migration mig2" will notice the new table definition. But it does not.
Any ideas why?
namespace MvcApplication4.Models
{
public class CmsContext: DbContext
{
public CmsContext()
: base("DefaultConnection")
{
}
public DbSet<CustomItem> CustomItems { get; set; }
}
[Table("CustomItems")]
public class CustomItem
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public int Ordinal { get; set; }
public String Title { get; set; }
public String Content { get; set; }
public String FilePath { get; set; }
}
}
Multi-tenancy is not supported in EF5 but is supported in EF6 where you can specify a context for which you want to enable migrations for like this:
Enable-Migrations -ContextTypeName {NameOfTheContextType}
See the migrations multi-tenancy feature spec on the Entity Framework codeplex site.