.Net Core Entity Framework Abstraction - c#

I have an .Net Core Class Library project which has a context file that uses Entity Framework. The context file looks like this;
public partial class Qcrr : DbContext
{
public virtual DbSet<AirWorthyNess> AirWorthyNess { get; set; }
public virtual DbSet<AwLog> AwLog { get; set; }
public virtual DbSet<AwserialNumbers> AwserialNumbers { get; set; }
public virtual DbSet<EmployeeInformation> EmployeeInformation { get; set; }
public virtual DbSet<Password256> Password256 { get; set; }
public virtual DbSet<Persistant> Persistant { get; set; }
public virtual DbSet<TblApplicationRights> TblApplicationRights { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
if (!optionsBuilder.IsConfigured)
{
optionsBuilder.UseSqlServer(#"my connection string");
}
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
/* my tables
.
.
.
*/
}
}
Now, I also have a simple .Net Core Console Application that references the class library dll for testing purposes. I want to be able to use the EF DbSet functionality as it is, within my console app without having to reference EF again. Of course if I try to use the context file directly, I have the following error;
Its telling me to reference Entity Framework again.
So my question is, what would be the best practice approach to abstract my dbcontext which lies within my Class Library ?
Would I need to implement the DbContext functionalities (scuh as Add, AddRange, Delete, IQueryable implementations (Select, Where, First...))?

Entity framework is already a good abstraction for DB.
if You add another layer, you always will be forced to add more and more functionality to your abstraction.
Good example is AsNoTracking function for EF. It is good for performance, but adding it's implementation to your abstraction without re-implementing whole EF logic is a big deal. Another example is Spatial data types, raw SQL queries and much more interesting functions that your business logic might require, but you can't use them, because of your abstractions. So don't add another layer.
In my opinion the solution is to use Repository pattern.

Related

Defining many-to-many connection defining ICollection<> only in one class

I have an .NET application with the validation logic outsourced to a .NET Core API. There are some models and logics that both of them use and I want them to use the same classes from a (.net standard) Nuget package. The main problem that I'm using Entity Framework code-first, and some of the common models are in database too but i don't want to include f.e. ApplicationUser in the nuget package.
There is a model with a many-to-many connection to ApplicationUser and I don't want to define the ICollection in it.
So my "local" class looks something like this:
public class ApplicationUser : IdentityUser
{
....
public ICollection<Institute> Institutes { get; set; }
....
}
And my "remote" class looks like this:
public class Institute
{
....
public ICollection<ApplicationUser> Users { get; set; }
....
}
But I don't want Institute to have this public ICollection<ApplicationUser> Users { get; set; } but I want the EF to map the many-to-many connection. If I delete it from the Institute class the next migration will delete the whole ApplicationUserInstitute connection table.
I have thought of some kind of inheritance solution but I think future development would be pain in the ass with it. Every possible solution is welcomed.
You need explicitly override OnModelCreating() in your context and specify Many-to-Many relation there:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Entity<ApplicationUser>()
.HasMany(s => s.Institues)
.WithMany()
.Map(cs =>
{
cs.MapLeftKey("UserRefId");
cs.MapRightKey("InstituteRefId");
cs.ToTable("UserInsitute");
});
}
I used entities from this article to generate schema. The only difference is that I removed public virtual ICollection<Student> Students { get; set; } from Course.

How to deal with many-to-many relationships in the general repository, unit of work pattern?

For my thesis I decided to create something in MVC and to challenge myself I added a DAL and BL layer. I created "services" in BL that allow me to work with my Entities.
I am really wondering if I understood the pattern correctly, because I am having issues dealing with many-to-many relationships - and especially how to use them properly.
This is my current implementation (simplified, to get the general idea):
PersonService: this class is my abstraction for using my entities (I have several entity factories as well). Whenever I need to add a Person to my DB, I use my service. I just noticed that mPersonRepository should probably be named differently.
public class PersonService : IService<Person> {
private UnitOfWork mPersonRepository;
public PersonService() => mPersonRepository = new UnitOfWork();
public void Add(Person aPerson) {
mPersonRepository.PersonRepository.Insert(aPerson);
mPersonRepository.Safe();
}
public void Delete(Guid aGuid) {
mPersonRepository.PersonRepository.Delete(aGuid);
mPersonRepository.Safe();
}
public Person Find(Expression<Func<Person, bool>> aFilter = null) {
var lPerson = mPersonRepository.PersonRepository.Get(aFilter).FirstOrDefault();
return lPerson;
}
public void Update(Person aPerson) {
mPersonRepository.PersonRepository.Update(aPerson);
mPersonRepository.Safe();
}
}
public interface IService<TEntity> where TEntity : class {
void Add(TEntity aEntity);
void Update(TEntity aEntity);
void Delete(Guid aGuid);
TEntity Find(Expression<Func<TEntity, bool>> aExpression);
TEntity FindByOid(Guid aGuid);
IEnumerable<TEntity> FindAll(Expression<Func<TEntity, bool>> aExpression);
int Count();
}
UnitOfWork: pretty much similar as the way Microsoft implemented it.
public class UnitOfWork : IUnitOfWork {
private readonly DbContextOptions<PMDContext> mDbContextOptions = new DbContextOptions<PMDContext>();
public PMDContext mContext;
public UnitOfWork() => mContext = new PMDContext(mDbContextOptions);
public void Safe() => mContext.SaveChanges();
private bool mDisposed = false;
protected virtual void Dispose(bool aDisposed) {
if (!mDisposed)
if (aDisposed) mContext.Dispose();
mDisposed = true;
}
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
private GenericRepository<Person> mPersonRepository;
private GenericRepository<Project> mProjectRepository;
public GenericRepository<Person> PersonRepository => mPersonRepository ?? new GenericRepository<Person>(mContext);
public GenericRepository<Project> ProjectRepository => mProjectRepository ?? new GenericRepository<Project>(mContext);
GenericRepository: just as before, it is very similar.
public class GenericRepository<TEntity> : IGenericRepository<TEntity> where TEntity : class {
internal PMDContext mContext;
internal DbSet<TEntity> mDbSet;
public GenericRepository(PMDContext aContext) {
mContext = aContext;
mDbSet = aContext.Set<TEntity>();
}
public virtual IEnumerable<TEntity> Get(
Expression<Func<TEntity, bool>> aFilter = null,
Func<IQueryable<TEntity>, IOrderedQueryable<TEntity>> aOrderBy = null,
string aProperties = "") {
var lQuery = (IQueryable<TEntity>)mDbSet;
if (aFilter != null) lQuery = lQuery.Where(aFilter);
foreach (var lProperty in aProperties.Split
(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)) {
lQuery = lQuery.Include(lProperty);
}
return aOrderBy != null ? aOrderBy(lQuery).ToList() : lQuery.ToList();
}
public virtual TEntity GetById(object aId) => mDbSet.Find(aId);
public virtual void Insert(TEntity aEntity) => mDbSet.Add(aEntity);
public virtual void Delete(object aId) {
var lEntity = mDbSet.Find(aId);
Delete(lEntity);
}
public virtual void Delete(TEntity aEntity) {
if (mContext.Entry(aEntity).State == EntityState.Detached) mDbSet.Attach(aEntity);
mDbSet.Remove(aEntity);
}
public virtual void Update(TEntity aEntity) {
mDbSet.Attach(aEntity);
mContext.Entry(aEntity).State = EntityState.Modified;
}
}
PMDContext: an implementation of DbContext.
public class PMDContext : DbContext {
public PMDContext(DbContextOptions<PMDContext> aOptions) : base(aOptions) { }
public DbSet<Person> Persons { get; set; }
public DbSet<Project> Projects { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder aOptions) {
if (!aOptions.IsConfigured) aOptions.UseSqlServer("<snip>");
}
}
Entities
public class Person {
public Person(<args>) {}
public Guid Oid { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
public class Project {
public Project(<args>) {}
public Guid Oid { get; set; }
public string Name { get; set; }
}
I use it all like the following:
var lPerson = Factory.CreatePerson(<args>);
var lPersonService = new PersonService();
lPersonService.Add(lPerson);
<..do some work..>
lPersonService.Update(lPerson)
Now I do not need to worry about calling Safe, or whatever. It works just fine, but now I ran into an issue: how do I deal with many-to-many relations in my Entities. For example my Person can have multiple Projects and my Project can have multiple Persons.
I updated my PMDContext to get a link table:
protected override void OnModelCreating(ModelBuilder aModelBuilder) {
aModelBuilder.Entity<PersonProject>().HasKey(x => new { x.PersonOid, x.ProjectOid });
}
Link table
public class PersonProject {
public Guid PersonOid { get; set; }
public Guid ProjectOid { get; set; }
}
And updated both my entities with the following property.
public ICollection<PersonProject> PersonProjects { get; } = new List<PersonProject>();
Now I am confused on how to use my linked table. I thought I could follow a similar approach like this:
var lPerson = PersonService.FindByOid(aPersonOid);
var lProject = ProjectService.FindByOid(aProjectOid);
var lPersonProject = new PersonProject() { PersonOid = aPersonOid,
ProjectOid = aProjectOid };
lPerson.PersonProjects.Add(lPersonProject);
lProject.PersonProjects.Add(lPersonProject);
PersonService.Update(lPerson);
ProjectService.Update(lProject);
But this ends up not doing anything to the PersonProject table in my DB. My guess is that I lack the code to actually write to that table, since I do not have a PersonProject service that handles this. I am confused.
How would I advance using my current approach, or what do I have to change? I am only a beginner w/ entity frameworks and already happy I got this far.
Any input is appreciated especially on the services -> pattern implementation. I must be doing something wrong.
Thanks!
You're not really using a service layer pattern. Your "service" is just a repository, which then uses your unit of work to access another repository. In short, you've got multiple layers of meaningless abstraction here, which will absolutely kill you in an app you have to maintain for any amount of time.
In general, you should not use the unit of work / repository patterns with ORMs like Entity Framework. The reason why is simple: these ORMs already implement these patterns. In the case of EF, the DbContext is your unit of work and each DbSet is a repository.
If you're going to use something like Entity Framework, my best advice is to just use it. Reference it in your app, inject your context into your controllers and such, and actually use the EF API to do the things you need to do. Isn't this creating a tight coupling? Yes. Yes it is. However, the point so many miss (even myself for a long time) is that coupling is already there. Even if you abstract everything, you're still dealing with a particular domain that you can never fully abstract. If you change your database, that will bubble up to your application at some point, even if it's DTOs you're changing instead of entities. And, of course you'll still have to change those entities as well. The layers just add more maintenance and entropy to your application, which is actually the antithesis of the "clean code" architecture abstractions are supposed to be about.
But what if you need to switch out EF with something else? Won't you have to rewrite a bunch of code? Well, yeah. However, that pretty much never happens. Making a choice on something like an ORM has enough momentum that you're not likely to be able to reverse that course no matter what you do, regardless of how many layers of abstractions you use. It's simply going to require too much time and effort and will never be a business priority. And, importantly, a bunch of code will have to be rewritten regardless. It's only a matter of what layer it's going to be done in.
Now, all that said, there is value in certain patterns like CQRS (Command Query Responsibility Segregation), which is an abstraction (and not a meaningless one, that). However, that only makes sense in large projects or domains where you need clear cut separation between things like reads and writes and/or event sourcings (which goes naturally with CQRS). It's overkill for the majority of applications.
What I would recommend beyond anything else if you want to abstract EF from your main application is to actually create microservices. These microservices are basically just little APIs (though they don't have to be) that deal with just a single unit of functionality for your application. Your application, then, makes requests or otherwise access the microservices to get the data it needs. The microservice would just use EF directly, while the application would have no dependency on EF at all (the holy grail developers think they want).
With a microservice architecture, you can actually check all the boxes you think this faux abstraction is getting you. Want to switch out EF with something else? No problem. Since each microservice only works with a limited subset of the domain, there's not a ton of code typically. Even using EF directly, it would be relatively trivial to rewrite those portions. Better yet, each microservice is completely independent, so you can switch EF out on one, but continue using EF on another. Everything keeps working and the application couldn't care less. This gives you the ability to handle migrations over time and at a pace that is manageable.
Long and short, don't over-engineer. That's the bane of even developers who've been in the business for a while, but especially of new developers, fresh out of the gates with visions of code patterns dancing in their heads. Remember that the patterns are there as recommended ways to solve specific problems. First, you need to ensure that you actually have the problem, then you need to focus on whether that pattern is actually the best way to solve that problem your specific circumstance. This is a skill - one you'll learn over time. The best way to get there is to start small. Build the bare minimum functionality in the most straight-forward way possible. Then, refactor. Test, profile, throw it to the wolves and drag back the blood-soaked remains. Then, refactor. Eventually, you might end up implementing all kinds of different layers and patterns, but you also might not. It's those "might not" times that matter, because in those cases, you've got simple, effortlessly maintainable code that just works and that didn't waste a ton of development time.

IdentityDbContext User DbSet Name

I've created a custom user inheriting from IdentityUser called Contacts, and my applications dbcontext inherits from IdentityDbContext like so:
public class Contact : IdentityUser<int, ContactLogin, ContactRole, ContactClaim>
{
public Contact()
{
}
}
public class dbcontext : IdentityDbContext<Contact, Role, int, ContactLogin, ContactRole, ContactClaim>
{
public dbcontext()
: base("dbcontext")
{
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// IdentityDbContext base - must be called prior to changing identity configuration
base.OnModelCreating(modelBuilder);
// custom identity table names and primary key column Id names
modelBuilder.Entity<Contact>().ToTable("Contacts").Property(p => p.Id).HasColumnName("ContactId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
modelBuilder.Entity<ContactRole>().ToTable("ContactRoles");
modelBuilder.Entity<ContactLogin>().ToTable("ContactLogins");
modelBuilder.Entity<ContactClaim>().ToTable("ContactClaims").Property(p => p.Id).HasColumnName("ContactClaimId");
modelBuilder.Entity<Role>().ToTable("Roles").Property(p => p.Id).HasColumnName("RoleId").HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
}
}
By default IdentityDbContext contains a Users DbSet. Is it possible to change the name of this DbSet to match the type that it's implementing, e.g Contacts?
It's not a big deal, but it would just be nice to refer to the DbSet using dbcontext.Contacts instead of dbcontext.Users.
Thanks.
The base IdentityDbContext uses: public virtual IDbSet<TUser> Users { get; set; } to expose the Users DbSet.
You'll need a similar property for your own implementation, e.g: public IDbSet<Contacts> Contacts { get; set; }
Update
Question was regarding renaming the existing DbSet of Contacts from Users to Contacts.
No, you can't do this out of the box. You could attempt to wrap it and expose it again, but this isn't really the right thing to do. See this question for an in depth discussion.
Just a note that if you decide to overwrite anything or add your own, the default EF implementation of UserStore will use the DbSet named Users. Just something to keep an eye on if you get unexpected behavior.
Generally what I tend to do is have a big separation of concerns right.
So I have:
public IDbSet<User> Users { get; set; }
This represents anyone who wants to log into my system. So now I want to model actual concepts into my database, concepts that relate to real world things. So I have a system administrator for example, I will create an entity for this.
public class SystemAdministrator
{
public string Name { get; set; }
public int LocationId { get; set; } // a complex representation of where this administrator works from
public int UserId { get; set; } // this is now a reference to their log in
}
Now my context will look like this:
public IDbSet<User> Users { get; set; }
public DbSet<SystemAdministrator> SystemAdministrators { get; set; } // I use DbSet because it exposes more methods to use like AddRange.
This means now my database has proper representations of real world concepts which is easy for everyone to develop against. I do the same for Clients or Employees.
This also means that I can move away from primitive obsession

Entity Framework 5 code-first configuration encapsulation

I was wondering (and I hate using the words 'Best Practice') - but is this a good way to approach configuration as it encapsulates the config for AAA?
I see a lot of examples where the OnModelCreating is a huge list of instructions for creating the database and long methods tell me something isn't quiet right.
public class MyContext : DbContext
{
public MyContext() : base("name=MyDb") { }
public DbSet<AAA> AAAs { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Configurations.Add(new AAA.Configuration());
}
}
And the class with a spot for it's config
public class AAA
{
[Key]
public int Id { get; set; }
[Required]
public string Details { get; set; }
internal class Configuration : EntityTypeConfiguration<AAA>
{
public Configuration()
{
// Set all the funky stuff here
}
}
}
I get that there probably isn't one right way. Before I commit a lot of time and tears I am looking for a reason why this might be absolutely the worst idea in the world or if there is a way to do something similar?
EDIT
A Colleague suggested this as an alternate method using a static property
public class AAA
{
[Key]
public int Id { get; set; }
[Required]
public string Details { get; set; }
public static EntityTypeConfiguration<AAA> Configuration
{
get { return new AAAConfiguration(); }
}
}
internal class AAAConfiguration : EntityTypeConfiguration<AAA>
{
public AAAConfiguration()
{
// Set all the funky stuff here
}
}
I like this as it gives me a bit more flexibility with how the configuration is instanced.
It depends. I am by now far enough to say that I don't care about db generation. It is nice and has advantages (platform independent) which I do not care about. it is limiting from using SQL Server fully - so it is back to database projects.
This is a world of compromises, and - sorry- a best practice comes with a TON of limitations there.
I personally don't see an issue in the approach you have taken. I have just recently resolved a similar dilema in my head, the only difference being is I have the EntityTypeConfiguration<T> classes inside my data layer and not within my model. I'm doing all the mapping logic in these mapping classes too; this means I don't have to decorate my model with EF specific attributes, keeping them totally persistence-ignorant.
With your approach, in the OnModelCreating method you only need to have one line per class that you want to persist, plus this code is only hit once if you don't clear the cache that EF creates, so it's only a kind of one-off bootstrap and therefore a long method isn't an issue?
I think your approach is fine, but I'm sure there will be some differing views on the subject.

Using the same classes for NHibernate and Script#?

I am about to start a project using NHibernate and Script#
NHibernate required that all properties be virtual, so I have my entity like this:
public partial class User
{
public virtual string Username { get; set; }
public virtual string PasswordHash { get; set; }
public virtual DateTime DateRegistered { get; set; }
}
But Script# build fails when it encountered partial and virtual.
Partial I can cope with but not having virtual will probably requires a redesign/thinking ahead.
My goal is to share code between the main models project and the front-end Script# project so I don't have to re-implement the model twice, have strong-typing support and refactoring support throughout the models and scripts etc. etc.
Is this possible? Has anyone done this before? What are some available options?
I would create a ViewModel, and use AutoMapper to perform mapping for you, then you can use Script# with ViewModel.

Categories