I have multiple object and some of them go to one schema "NewObjects" and the other go to "OldObjects" I want to be able to make what the NewObjects Schema is configurable from config file. Is there a way? Here is what I have.
namespace IDJC.Domain
{
[Table("Agency", Schema = "NewObjects")]
public class Agency
{
public int AgencyId { get; set; }
public string AgencyName { get; set; }
}
}
Yes, through fluent api. Check the part: Mapping an Entity Type to a Specific Table in the Database:
For example, if you create a setting in your project (through Properties->Settings) name MySchemaName, you will be able to access it in your DbContext derived class. So when you override OnModelCreating you will be able to do something like:
modelBuilder.Entity<Agency>()
.ToTable("Agency", Properties.Settings.Default.MySchemaName);
Related
I just stumbled onto Audit.Net and I'm hooked. I went through the Audit.Net Entity Framework (6) documentation and am a bit lost in the output part.
My solution is a bit many-layers design:
Mvc 5 website
Wcf Client
Using WcfClientProxyGenerator
Wcf Service
Separate IService Contracts Library
All interfaces expose BDOs
Business Logic
Seperate BDO Library
Data Access
Reference EF6
Reference Audit.Net
DTOs
Entity Framwework Library
Has EDMX only
Reference Audit.Net
Reference: My EDMX is named Focus
Usage
I manage to modify the FocusModel.Context.tt from:
partial class <#=code.Escape(container)#> : DbContext
To:
partial class <#=code.Escape(container)#> : Audit.EntityFramework.AuditDbContext
Configuration
I found the default setting for Mode, IncludeEntityObjects, & AuditEventType were to my liking. the attribute for Include/Ignore entities/properties were straightforward as well.
Output
This is where I'm confused. I need to audit to the same database preferably to Audit tables for selected entities. Every entity in my database has composite PKs. How do I set the output mode in this scenario? Also, in my solution setup, the starting point for all projects that are behind the WCF Service is the WCF service itself. Does this mean that the point to Fluent-API-configure Audit.Net is here?
Have you seen the main Audit.NET documentation, specifically the output data providers?
I need to audit to the same database preferably to Audit tables for selected entities. Every entity in my database has composite PKs.
So you can use the EF data provider. It works with any kind of primary key.
How do I set the output mode in this scenario?
I'm not sure what do you mean by output mode, but I'm guessing you ask about OptIn/OptOut to ignore your audit entities to be audited. If that's the case you have multiple options, like using AuditIgnore attribute on your audit POCO classes, or via the fluent-api OptIn()/OptOut() methods. See example below.
The starting point for all projects that are behind the WCF Service is the WCF service itself. Does this mean that the point to Fluent-API-configure Audit.Net is here?
You can configure the Audit.NET library in any place, but you must do it before any audit event creation, so it is recommended to be on your startup code, as soon as your app or service starts.
Sample code
The following is a minimal example showing how you can configure the Audit.NET and Audit.EntityFramework libraries.
Suppose you have the following schema:
public class Student
{
public int PK_1 { get; set; }
public string PK_2 { get; set; }
public string Name { get; set; }
}
public class Student_Audit
{
public int PK_1 { get; set; }
public string PK_2 { get; set; }
public string Name { get; set; }
public DateTime AuditDate { get; set; }
public string AuditAction { get; set; }
}
public class SchoolContext : AuditDbContext
{
protected override void OnModelCreating(ModelBuilder modelBuilder) //<--Tip: its not DbModelBuilder, its Microsoft.EntityFrameworkCore.ModelBuilder
{
modelBuilder.Entity<Student>().HasKey(c => new { c.PK_1, c.PK_2 });
modelBuilder.Entity<Student_Audit>().HasKey(c => new { c.PK_1, c.PK_2, c.AuditDate });
}
public DbSet<Student> Students { get; set; }
public DbSet<Student_Audit> Students_Audit { get; set; }
}
You can configure the library on your startup code as follows:
// Setup audit to use the EF data provider
Audit.Core.Configuration.Setup()
.UseEntityFramework(_ => _
.AuditTypeExplicitMapper(m => m
// Map Student to Student_Audit
.Map<Student, Student_Audit>((ev, ent, studentAudit) =>
{
//add the action name and the date to the audit entity
studentAudit.AuditAction = ent.Action;
studentAudit.AuditDate = DateTime.UtcNow;
})));
// Configure the EF audit behavior
Audit.EntityFramework.Configuration.Setup()
.ForContext<SchoolContext>(_ => _.IncludeEntityObjects())
.UseOptOut()
.Ignore<Student_Audit>(); // Do not audit the audit tables
And a test case:
using (var db = new SchoolContext())
{
db.Database.EnsureCreated();
var st = new Student() { PK_1 = 1, PK_2 = "one", Name = "John" };
db.Students.Add(st);
db.SaveChanges();
}
Will generate the following:
I am a bit lost right now... I've never seen this much divergent information regarding solution to the problem. But let us start from the beginning.
I am using ASP.NET MVC with Repositories injected to Controllers, thanks to the Ninject. I have 2 simple Entities: Admin with a list of created blog entries and Entries with one virtual Admin field.
Admin:
public class Admin
{
[Key, ScaffoldColumn(false)]
public int Id { get; set; }
[Required(ErrorMessage = "Zły login.")]
[StringLength(20), MinLength(3)]
[RegularExpression(#"^[a-zA-Z0-9]*$", ErrorMessage = "Special characters are not allowed.")]
public string Login { get; set; }
[Required(ErrorMessage = "Złe hasło.")]
[StringLength(20, MinimumLength = 3)]
[DataType(DataType.Password)]
[Display(Name = "Hasło")]
public string Password { get; set; }
public virtual List<Entry> CreatedEntries { get; set; } // napisane aktualności przez danego admina
}
Entry:
public class Entry
{
[Key, ScaffoldColumn(false)]
public int Id { get; set; }
[StringLength(200, MinimumLength = 2)]
[DataType(DataType.Text)]
[Display(Name = "Tytuł")]
public string Title { get; set; }
[Required, StringLength(2000), MinLength(3)]
[Display(Name = "Treść")]
[UIHint("tinymce_jquery_full"), AllowHtml]
public string Text { get; set; }
public virtual Admin Admin { get; set; }
}
You probably know where it is going, since this problem is... "classic" on stackoverflow.
In the Controller I want to bind one object to another:
entry.Admin = repAdmins.GetAdmin(User.Identity.Name);
repEntries.AddEntry(entry);
In the repository:
public void AddEntry(Entry entry)
{
db.Entries.Add(entry);
db.SaveChanges();
}
Of course I can't do that, because of famous "An entity object cannot be referenced by multiple instances of IEntityChangeTracker", which is a result of having separate database contexts in each repository.
When I was searching for a solution I already knew that probably the best way to solve it is to use one common context. And then I discovered Unit Of Work pattern. But here's when the real problems starts.
On many sites the solution to this is a bit different.
The repositories must have common generic interface (which I don't want to use, because I don't need to have each CRUD operation on each Entity, plus sometimes I need to have extra methods like "IfExists", etc.)
On few sites I've read that this whole abstraction is not needed, since abstraction is already provided with Entity Framework and UoW is implemented in DbContext (whatever that means)
The Unit Of Work pattern (at least from examples on the internet) seems to be a real pain for me...
I need some guidance... I learn ASP.NET MVC for only a year. For me it seems like it's a "triumph of form over content". Because... What I simply need is to bind one object to another. I'm starting to think that it was better when I simply had a context object in the Controller and I didn't need to build Eiffel Tower to achieve what's mentioned above :\ However I like idea of repositories...
I'll open by simply answering the question straight-out. Simply, your repository should take the context as a dependency (it should have a constructor that accepts a param of type DbContext). Your context should be managed by Ninject, and then injected into your repository and/or your controller. That way, everything always uses the same context. You should do all this in "request" scope, so that the context is specific to the current request.
That said, I'd like to hit some of your other points. First, a repository is just a method of access. It really shouldn't be dependent on the entity. It's okay to have methods that you don't intend to use on a particular entity: just don't use them. However, if you do want to enforce this, you can always use generic constraints and interfaces. For example, let's say you don't want update available on a particular entity. You could have interfaces like:
public interface ICreateable
{
}
public interface IUpdateable : ICreateable
{
}
Then, your entity that should not be updated will implement only ICreateable while other entities (which allow update) would implement IUpdateable (which by interface inheritance, also implement ICreateable). Finally, you would add constraints on your repository methods:
public void Create<TEntity>(TEntity entity)
where TEntity : class, ICreateable
public void Update<TEntity>(TEntity entity>)
where TEntity : class, IUpdateable
Since, the entity in question only implements ICreatable, it will not be eligible to be used as a type param to Update, so there's then no way to utilize that method.
Next, the advice to not use the repository/UoW patterns with Entity Framework is indeed because Entity Framework already implements these patterns. The repository pattern exists as a way to contain all the database querying logic (constructing SQL statements and such) in one place. That is the "abstraction" we're talking about here. In other words, instead of directly constructing SQL statements in your application code, that code is abstracted away into a repository. However, this is exactly what Entity Framework does, which is why you don't need to do it again. The Unit of Work pattern exists as a method to orchestrate the work of multiple repositories, allowing things like transactions. However, again, Entity Framework does all this.
The only reason to add any further abstraction is if you want to abstract the actual provider, i.e. Entity Framework itself. For example, you could have an interface like IRepository and then create implementations like EntityFrameworkRepository, NHibernateRepository, WebApiRepository, etc. Your application would only ever depend on IRepository, and you could then sub in different implementations as needed. If you're not going to do this, or you will always be using Entity Framework, then you might as well just use your context directly. Any further abstraction is just something else to maintain with no benefit at all to your application.
Finally, yes, the Unit of Work pattern is a real pain to everyone, not just you. Which is why I forgo it entirely. I use what I call a "truly generic repository", which utilizes generic methods and interfaces to handle any entity I want to throw at it. That means it acts not only as a repository but also a unit of work as well. You only need one instance per context and it's provider-agnostic. For more information check out the article I wrote on the subject over on my website.
The following example shows how to use the same context within multiple repositories. To simplify it, I did not use interfaces and nor did I use a container to inject dependencies.
Controller class:
public class HomeController : Controller
{
Context context;
AdminRepository adminRepository;
EntryRepository entryRepository;
public HomeController()
{
context = new Context();
adminRepository = new AdminRepository(context);
entryRepository = new EntryRepository(context);
}
// GET: Home
public ActionResult Index()
{
string login = "MyLogin";
Admin admin = adminRepository.GetAdmin(login);
Entry entry = new Entry() { Admin = admin};
entryRepository.AddEntry(entry);
return View(entry);
}
}
Repositories:
public class AdminRepository
{
Context context;
public AdminRepository(Context context)
{
this.context = context;
// This seeds the database
Admin admin = new Admin() { Login = "MyLogin" };
this.context.Admins.Add(admin);
this.context.SaveChanges();
}
public Admin GetAdmin(string login)
{
return context.Admins.Where(a => a.Login == login).FirstOrDefault();
}
}
public class EntryRepository
{
Context context;
public EntryRepository(Context context)
{
this.context = context;
}
public void AddEntry(Entry entry){
context.Entrys.Add(entry);
context.SaveChanges();
}
}
Context class:
public class Context : DbContext
{
public Context()
{
Database.SetInitializer<Context>(new DropCreateDatabaseAlways<Context>());
Database.Initialize(true);
}
public DbSet<Admin> Admins { get; set; }
public DbSet<Entry> Entrys { get; set; }
}
Modified Models:
public class Admin
{
public int Id { get; set; }
public string Login { get; set; }
}
public class Entry
{
public int Id { get; set; }
public virtual Admin Admin { get; set; }
}
I have an ASP.NET 5 web api, and I was hoping to use a single dbcontext for multiple models. These models point to tables with different schemas in my database.
The models below contain multiple classes
Auth
Study
Simplified a little: Auth.cs
public class MyContext : DbContext
{
public DbSet<Auth.App> Apps { get; set; }
public DbSet<Auth.Permission> Permissions { get; set; }
public DbSet<Study.StudyLink> StudyLinks { get; set; }
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
foreach (var entity in modelBuilder.Model.GetEntityTypes())
{
if (entity.Name.Contains("Auth+"))
{
modelBuilder.HasDefaultSchema("auth"); // Switch to the auth schema
modelBuilder.Entity(entity.Name).ToTable(entity.Name.Replace("myproject.Models.Auth+", string.Empty));
}
if (entity.Name.Contains("Study+"))
{
modelBuilder.HasDefaultSchema("study"); // Switch to the study schema
modelBuilder.Entity(entity.Name).ToTable(entity.Name.Replace("myproject.Models.Study+", string.Empty));
}
}
}
Using just the Auth model, I was able to change the default schema and can access the tables no problem.. when I add the Study model, the modelBuilder.Model.GetEntityTypes() foreach brings up both the Auth and Study models, so is switching the default schema, meaning I can't access the Auth schema because it switches to study.
Is there some way I can apply the schema without using HasDefaultSchema() or do I need to create a new context for each schema I use in my database?
Thanks
You can add your schema to the .ToTable("tableName", "schemaName"):
if (entity.Name.Contains("Auth+"))
{
modelBuilder.Entity(entity.Name).ToTable(entity.Name.Replace("myproject.Models.Auth+", string.Empty),"auth");
}
https://msdn.microsoft.com/en-us/data/jj591617.aspx?f=255&MSPPError=-2147217396#2.3
I'm new to Entity framework and Repository pattern. I'm trying to implement Repository Decorator pattern which contain basically Auditable and Archivable classes and extends the Attribute class. But when I add them on any entity class as:
[Auditable]
public class Student{
public int Id;
public string Name;
}
Using entity framework code first approach, the entity 'Student' supposed to generate columns Id,Name and the columns CreatedBy, Created, UpdatedBy and Updated from IAuditable interface. But what it was generating is only columns Id and Name.
So what is the correct way of implementing Repository Decorator pattern using entity framework and how to apply Auditable attribute on entity classes.?
Here I'm providing links to get some idea about repository decorator pattern.
https://efpatterns.codeplex.com/discussions/282699
https://efpatterns.codeplex.com/
Here is AuditableAttribute class extending Attribute:
using System;
namespace EntityFramework.Patterns.Extensions
{
public class AuditableAttribute : Attribute { }
}
Generic AuditableRepository class:
using System;
using System.Threading;
using EntityFramework.Patterns.Extensions;
namespace EntityFramework.Patterns.Decorators
{
public class AuditableRepository<T> : RepositoryDecoratorBase<T>
where T : class
{
public AuditableRepository(IRepository<T> surrogate) : base(surrogate) {
}
public override void Insert(T entity)
{
IAuditable auditable = entity as IAuditable;
if (auditable != null)
{
auditable.CreatedBy = Thread.CurrentPrincipal.Identity.Name;
auditable.Created = DateTime.Now;
}
base.Insert(entity);
}
public override void Update(T entity)
{
IAuditable auditable = entity as IAuditable;
if (auditable != null)
{
auditable.UpdatedBy = Thread.CurrentPrincipal.Identity.Name;
auditable.Updated = DateTime.Now;
}
base.Update(entity);
}
}
}
Here is the interface.
using System;
namespace EntityFramework.Patterns.Extensions
{
public interface IAuditable
{
string CreatedBy { get; set; }
DateTime? Created { get; set; }
string UpdatedBy { get; set; }
DateTime? Updated { get; set; }
}
}
So, what it would seem you have there is some dead code (or, more accurately, some not-yet-live code): it appears the author stubbed this out as a good idea some years ago, and it's been left on the vine ever since. You can see his last commit was almost 1.5 years ago, and the last one before that was almost the same time span.
Something that's not quite as widely downloaded from nuget.org but is more actively maintained is the excellent Highway.Data Framework, which my company uses on our projects – it even has an IAuditableInterceptor that's fully implemented! (Caveat: wish I could say that I've actually used this feature, but the rest of the framework is top-notch.)
Even better – if you're just learning EF – start with the basic EF6 nuget package and get comfortable with that first. That way, you won't be left guessing whether EF is fouling you up, or some unimplemented, third-party, library.
I have an InvoiceInputModel with a ProjectId property which is a reference to a Project entity. Ideally, I want AutoMapper to be able to map an entire Invoice entity from an InvoiceInputModel, which looks like this:
public class InvoiceInputModel
{
public Guid Id { get; set; }
public DateTime Date { get; set; }
public string Reference { get; set; }
public Guid ProjectId { get; set; }
}
Obviously the following is bad:
Mapper.CreateMap<InvoiceInputModel, Invoice>()
.ForMember(src => src.Project, opt => opt.MapFrom(
dest => _unitOfWork.CurrentSession.Get<Project>(dest.ProjectId)
)
);
How do I tell AutoMapper that invoice.Project should be mapped to a Project entity based off of the ProjectId property in InvoiceInputModel while preserving loose coupling?
Invoice/Edit in my InvoiceController:
[HttpPost]
[Authorize]
public ActionResult Edit(InvoiceInputModel invoiceInputModel)
{
var invoice = _unitOfWork.CurrentSession.Get<Invoice>(invoiceInputModel.Id);
Mapper.Map<InvoiceInputModel, Invoice>(invoiceInputModel, invoice);
invoice.Project = _unitOfWork.CurrentSession.Get<Project>(invoiceInputModel.ProjectId);
// I want AutoMapper to do the above.
_unitOfWork.CurrentSession.SaveOrUpdate(invoice);
_unitOfWork.Commit();
return View(invoice);
}
I spotted something about "Resolvers" and ResolveUsing, but I have no experience using it.
How do I tell AutoMapper to do this while preserving loose coupling between my entity models, input models and view models? Or is there a better way?
How do I tell AutoMapper that invoice.Project should be mapped to a Project entity based off of the ProjectId property in InvoiceInputModel while preserving loose coupling?
You can't. If AutoMapper is going somewhere else to fetch data, then it's not loose coupled.
You're not modifying the Project in this particular View anyway - why do you need to set the relationship to Project, isn't nHibernate smart enough to see that property hasn't changed, and not do anything?
I personally have entities in viewmodels instead of IDs, so that binding happens automatically.
http://sprokhorenko.blogspot.com/2011/03/bind-to-entity-id.html