Entity Framework AddOrUpdate - c#

I tried to insert the data into database from Facebook Graph search API by using EF AddOrUpdate. It is weird the following exception happened.
Violation of PRIMARY KEY constraint 'PK_dbo.Posts'. Cannot insert duplicate key in object 'dbo.Posts'. The duplicate key value is (100000544976851_913461492015341).
The statement has been terminated.
The code is very simple:
H2GO db2 = new H2GO();
if (obj != null)
{
ICollection<Post> posts = new Collection<Post>();
foreach (var data in obj.data)
{
var post = new Post
{
ID = data.id,
Tag = tag,
Content = data.message,
User = data.from.name,
Type = 2,
TagDate = Convert.ToDateTime(data.created_time),
};
db2.Posts.AddOrUpdate(p => p.ID, post);
}
db2.SaveChanges();

I see it has been a while, but I actually had this happen when I marked my model incorrectly and had a two part key and the database had only a one part key. So my model said this:
/// <summary>
/// Gets or sets the user identifier.
/// </summary>
/// <value>
/// The user identifier.
/// </value>
[Key]
public Guid UserId { get; set; }
/// <summary>
/// Gets or sets the plan identifier.
/// </summary>
/// <value>
/// The plan identifier.
/// </value>
[Key]
public string PlanId { get; set; }
However, a user can only have one plan at a time, so the database said this:
It was a dumb mistake on my part and one I found quickly, but ... hopefully this helps someone out.

Related

EF6 specify order of tables in Migration

In my database I have a couple tables with multiple PKs, which are each FKs.
Below is the C# definition of one such Entity:
/// <summary>
/// Represents a permission record in the client database.
/// Contains information on which <see cref="User"/> has access to which <see cref="Company"/> and which <see cref="Module"/>.
/// </summary>
public class Permission
{
/// <summary>
/// Gets or sets the unique identifier of the <see cref="User"/> to which the <see cref="Permission"/> is linked.
/// </summary>
public Guid UserId { get; set; }
/// <summary>
/// Gets or sets the unique identifier of the <see cref="Company"/> to which the <see cref="Permission"/> is linked.
/// </summary>
public Guid CompanyId { get; set; }
/// <summary>
/// Gets or sets the unique identifier of the <see cref="Module"/> to which the <see cref="Permission"/> is linked.
/// </summary>
public Guid ModuleId { get; set; }
/// <summary>
/// Gets the date and time at which the <see cref="Permission"/> was created.
/// </summary>
public DateTime CreatedAt { get; } = DateTime.UtcNow;
/// <summary>
/// Gets the date and time at which the <see cref="Permission"/> was last updated.
/// </summary>
public DateTime UpdatedAt { get; } = DateTime.UtcNow;
/// <summary>
/// Gets or sets a concurrency token used to prevent conflicting edits in a <see cref="Permission"/> entity.
/// </summary>
[SuppressMessage("ReSharper", "AutoPropertyCanBeMadeGetOnly.Global", Justification = "Used by Entity Framework.")]
public byte[] RowVersion { get; set; } = null!;
/// <summary>
/// Gets or sets the <see cref="User"/> to which the <see cref="Permission"/> is linked through <see cref="UserId"/>.
/// </summary>
public User User { get; set; } = null!;
/// <summary>
/// Gets or sets the <see cref="Company"/> to which the <see cref="Permission"/> is linked through <see cref="CompanyId"/>.
/// </summary>
public Company Company { get; set; } = null!;
/// <summary>
/// Gets or sets the <see cref="Module"/> linked to the <see cref="Permission"/> through <see cref="ModuleId"/>.
/// </summary>
public Module Module { get; set; } = null!;
}
The FluentAPI configuration for the Permission entity is as below:
public class PermissionConfiguration : IEntityTypeConfiguration<Permission>
{
/// <inheritdoc />
public void Configure(EntityTypeBuilder<Permission> builder)
{
builder = builder ?? throw new ArgumentNullException(nameof(builder));
builder.HasKey(permission => new
{
permission.UserId,
permission.CompanyId,
permission.ModuleId,
});
builder.Property(p => p.CreatedAt)
.HasDefaultValueSql("getdate()")
.ValueGeneratedOnAdd()
.IsRequired();
builder.Property(p => p.UpdatedAt)
.HasDefaultValueSql("getdate()")
.ValueGeneratedOnAddOrUpdate()
.IsRequired();
builder.Property(p => p.RowVersion)
.IsRowVersion();
// Configures one-to-many FK relationship with User table.
builder.HasOne(p => p.User)
.WithMany(u => u.Permissions)
.HasForeignKey(p => p.UserId)
.OnDelete(DeleteBehavior.ClientCascade) // deletions are handled by context instead of SQL behaviour.
.IsRequired();
// Configures one-to-many FK relationship with Company table.
builder.HasOne(p => p.Company)
.WithMany(c => c.Permissions)
.HasForeignKey(p => p.CompanyId)
.OnDelete(DeleteBehavior.ClientCascade) // deletions are handled by context instead of SQL behaviour.
.IsRequired();
// Configures one-to-many FK relationship with Module table.
builder.HasOne(p => p.Module)
.WithMany(m => m.Permissions)
.HasForeignKey(p => p.ModuleId)
.OnDelete(DeleteBehavior.ClientCascade) // deletions are handled by context instead of SQL behaviour.
.IsRequired();
}
}
Every time I apply a new migration, Entity Framework crashes on a FK exception.
At first I figured to set the ON DELETE behaviour for the Permission entity to ClientCascade, so that the context would handle deleting the records.
This has however not fixed it, and it seems the real problem is that EF tries to truncate the rows from either the User, Company or Module tables before getting to the Permission table.
I figured this would not be a new problem and the use case does not seem very far fetched to me, however I have not been able to find a solution to this.
Is there a way to specify an order in which tables are truncated in the Down method of migrations?
I would assume instructing EF to first empty the Permission table before the Company, User and Module tables would solve this issue?
Thanks in advance!

EF Core OnDelete Not Available

I have an issue in our system where a process is attempting to replace a record and it causes a FK Exception and fails. We are using Microsoft.EntityFrameworkCore 2.2.2 in a .Net Standard 2.0 library. Most of the code was ported from an existing project that was not .Net Core.
I am trying to add cascade delete to the following model:
modelBuilder.Entity<TermEntity>()
.ToTable("Term", SchemaName)
.HasKey(k => new { k.TermId, k.TenantId });
by adding the following:
modelBuilder.Entity<TermEntity>()
.ToTable("Term", SchemaName)
.HasKey(k => new { k.TermId, k.TenantId });
.OnDelete(DeleteBehavior.Cascade);
but I then get an error C1061 'KeyBuilder' does not contain a definition for OnDelete which makes sense as that is what is returned from HasKey and the OnDelete is on ReferenceCollectionBuilder. None of the methods used above return one of those and all of them (yes I have tried moving it around) give a similar error. The signature of the method this is in looks like:
protected override void OnModelCreating(ModelBuilder modelBuilder)
When I look up some EF Core tutorials I don't see the methods I am using and instead I see HasOne, WithMany etc usually with OnDelete at the end of the chain. I also thought I read that Cascade was the default so not sure why I have the issue in the first place if that is the case.
Can someone point me in the right direction to getting this fixed please.
The TermEntity looks like:
public class TermEntity
{
/// <summary>
/// Gets or sets the term identifier.
/// </summary>
/// <value>
/// The term identifier.
/// </value>
public short TermId { get; set; }
/// <summary>
/// Gets or sets the Tenant identifier.
/// </summary>
/// <value>
/// The Tenant range identifier.
/// </value>
public short TenantId { get; set; }
/// <summary>
/// Gets or sets the value.
/// </summary>
/// <value>
/// The value.
/// </value>
public int Value { get; set; }
}
NB: I was asked to provide the class I was using in the example and realised that I had posted the wrong one. TermEntity is the class I am having problems with.

How do I retrieve a single record on Microsoft CRM using c# if I don't know the GUID?

We have a vendor solution here where it uses Microsoft Dynamics CRM as base. The application includes this custom entity which has the following attributes (truncated to only show the relevant bits)
relationship entity (works like a list of values. like values for populating a dropdown list)
relationshipid (guid datatype. primary key)
description (string and sample values would include "staff" or "customer" or "visitor" and etc)
I want to retrieve a single record from the entity. something like:
select * from relationship where description like "staff%"
I know there's a Retrieve function but I need the guid to use that. I want to emulate the SQL above without having to possibly use QueryExpression. I want to get an object of type Entity instead of EntityCollection which is what a QueryExpression will give me.
thanks a lot :)
The SDK doesn't provide a method to return a single entity unless you have its Id. But you can write an extension method to help yourself out.
Here is what I use:
/// <summary>
/// Gets the first entity that matches the query expression. Null is returned if none are found.
/// </summary>
/// <typeparam name="T">The Entity Type.</typeparam>
/// <param name="service">The service.</param>
/// <param name="qe">The query expression.</param>
/// <returns></returns>
public static T GetFirstOrDefault<T>(this IOrganizationService service, QueryExpression qe) where T : Entity
{
qe.First();
return service.RetrieveMultiple(qe).ToEntityList<T>().FirstOrDefault();
}
/// <summary>
/// Converts the entity collection into a list, casting each entity.
/// </summary>
/// <typeparam name="T">The type of Entity</typeparam>
/// <param name="col">The collection to convert</param>
/// <returns></returns>
public static List<T> ToEntityList<T>(this EntityCollection col) where T : Entity
{
return col.Entities.Select(e => e.ToEntity<T>()).ToList();
}
The GetFirstOrDefault ensures that the QE is only going to retrieve one entity. The ToEntityList Casts each entity to the early bound type being returned.
So the call would look like:
var contact = service.GetFirstOrDefault<Contact>(qe);
just check if the EntityCollection contains one element, if true returns the single element
EntityCollection results = service...
if (results.Entities.Count == 1) {
return results.Entities[0];
}
To add to the other answers, even though you will still get an EntityCollection in return to a query expression, you can specify a top count to only retrieve 1 record as an alternative.
QueryExpression qeOpportunity = new QueryExpression();
qeOpportunity.EntityName = "opportunity";
qeOpportunity.ColumnSet = new ColumnSet(new string[] { "sp_shippingmethod_lookup", "description" });
qeOpportunity.TopCount = 1;
// Add other Conditions here with qeOpportunity.Criteria.AddCondition()....
EntityCollection ecOpportunity = service.RetrieveMultiple(qeOpportunity);
if (ecOpportunity.Entities.Count > 0)
{
string description = ecOpportunity.Entities[0].GetAttributeValue<string>("description");
EntityReference myShippingMethod = ecOpportunity.Entities[0].GetAttributeValue<EntityReference>("sp_shippingmethod_lookup");
}

Where returns wrong record

UPDATE
I've just had a thought that may well be relevant to this issue. I'm using a code first approach with this project. Originally my ZoneMapping class was defined as you can see below, however the database only had a single PrimaryKey field in the database. I believe because EF hadn't interpreted the data quite correctly.
At this point I made a modification to my migration SQL script output to add the additional primary key that I applied to the database. I've just updated the migration instead from:
CreateTable(
"dbo.NetC_EF_ZoneMapping",
c => new
{
PostcodeKey = c.String(nullable: false, maxLength: 128),
Zone_ID = c.Int(),
})
.PrimaryKey(t => t.PostcodeKey)
.ForeignKey("dbo.NetC_EF_Zone", t => t.Zone_ID)
.Index(t => t.Zone_ID);
I've just tried adding an additional PrimaryKey manually in the migration after the PostcodeKey one has been defined.
.PrimaryKey(t => t.Zone_ID)
Unfortunately I'm still getting my error - I'm assuming this migration isn't used to build the EF 'model' in code, but I'm wondering if it thinks that there can only be a single entry with any given PostcodeKey which may explain the situation?
I'm posting a new question based on Linq Except not functioning as expected - duplicate items because I feel that enough has been discovered that the question is invalid, and Except is not the problem at all.
The problem I have is that I have a Linq Where clause that seems to be returning the wrong data. The data in my database looks like:
The class that represents this data has a compound key:
/// <summary>
/// Represents a mapping between a postcode and a zone
/// </summary>
[Table("NetC_EF_ZoneMapping")]
public class ZoneMapping
{
/// <summary>
/// Gets or sets the postcode identifier
/// </summary>
[Key]
public String PostcodeKey { get; set; }
/// <summary>
/// Gets or sets the Zone identifier
/// </summary>
[Key]
public Zone Zone { get; set; }
}
So I'm executing the following code, which results in different IDs:
var result = this.context.ZoneMappings.Include("Zone").Where(z => z.Zone.ID == 257 && z.PostcodeKey == "2214");
var result2 = new FreightContext().ZoneMappings.Include("Zone").Where(z => z.Zone.ID == 257 && z.PostcodeKey == "2214");
if (result.First().Zone.ID != result2.First().Zone.ID)
throw new InvalidOperationException();
The SQL (or ToString() for these two items is identical). So the only difference is that one is a new context, while the other has been passed in and used for some other stuff. The code that creates the context returning the wrong result is:
// Copy the contents of the posted file to a memory stream
using (StreamReader sr = new StreamReader(fileUpload.PostedFile.InputStream))
using (FreightContext context = new FreightContext())
{
// Attempt to run the import
ZoneMappingCSVImporter importer = new ZoneMappingCSVImporter(sr, context, System.Globalization.CultureInfo.CurrentUICulture);
var items = importer.GetItems().ToList();
importer.SaveItems(items);
this.successBox.Value = "Import completed and added " + items.Count() + " zones mappings.";
}
This then registers a ClassMap in the library that I'm using where:
public ZoneMappingCSVImporter(TextReader textReader, FreightContext context, CultureInfo culture)
: base(textReader, context, culture)
{
this.reader.Configuration.RegisterClassMap(new ZoneMappingMap(this.context));
}
I do a lookup using the context:
/// <summary>
/// Initializes a new instance of the <see cref="ZoneMap"/> class.
/// </summary>
public ZoneMappingMap(FreightContext context)
{
if (context == null)
throw new ArgumentNullException("context");
Map(m => m.PostcodeKey);
Map(m => m.Zone).ConvertUsing(row =>
{
// Grab the name of the zone then go find this in the database
String name = row.GetField<String>("Zone");
return context.Zones.Where(z => String.Compare(z.Name, name, true) == 0).FirstOrDefault();
});
}
I can't see anything strange going on here, I've verified the SQL generated by Entity Framework, verified the database is the same one - I can't understand why the wrong record would be returned. Can anyone shed any light on this?
The explanation for this problem is most likely the following:
Your way to define composite primary key in your entity is incorrect. With your current model EF only considers ZoneMapping.PostcodeKey as the primary key. More on this and how to fix it below.
You get a wrong result in the case when the corresponding context already contains the entity with PostcodeKey == "2214" and Zone_ID == 256 before you run your query. (I guess you never had a wrong result2.) When EF loads entities from the database it always looks after the query if an entity with the same key already exists in the context. If yes, the queried entity is thrown away and instead the attached entity is added to the result collection. In your case you are querying for PostcodeKey == "2214" and Zone_ID == 257. After the query EF picks the values of the primary key from the result row. But because EF "thinks" the primary key is only PostcodeKey == "2214" it searches for an attached entity with that key value and finds the entity with PostcodeKey == "2214", but Zone_ID == 256 and returns that as the result to you. You never get this problem with result2 because the corresponding context is new and empty, so EF will return the result that just has been loaded, not any older attached entity.
If you want to define a composite key you must have scalar properties for both key parts. You cannot use a navigation property like ZoneMapping.Zone as a key part. It means that you must have a property for your column Zone_ID in the model class (in addition to the navigation property Zone):
public class ZoneMapping
{
public String PostcodeKey { get; set; }
public int Zone_ID { get; set; }
public Zone Zone { get; set; }
}
Then in order to define a composite key with data annotations you must use the Column(Order = n) attribute as already shown in #Jonas Jämtberg's answer. You should also apply the ForeignKey attribute to Zone_ID because the underscore makes the property name "unconventional" so that EF won't detect it as FK by convention:
public class ZoneMapping
{
[Key, Column(Order = 0)]
public String PostcodeKey { get; set; }
[Key, ForeignKey("Zone"), Column(Order = 1)]
public int Zone_ID { get; set; }
public Zone Zone { get; set; }
}
The migration class that is generated by EF with this mapping should have a primary key definition that looks like this:
.PrimaryKey(t => new { t.PostcodeKey, t.Zone_ID })
...not like .PrimaryKey(t => t.PostcodeKey).PrimaryKey(t => t.Zone_ID) that you tried unsuccessfully to fix the problem.

How to generalise access to DbSet<TEntity> members of a DbContext?

I have a DbContext with several of the following type of members:
public DbSet<JobLevel> JobLevels { get; set; }
public DbSet<Country> Countries { get; set; }
public DbSet<Race> Races { get; set; }
public DbSet<Language> Languages { get; set; }
public DbSet<Title> Titles { get; set; }
All these are where T: IdNamePairBase, which has Id and Name members only. I am trying desperately to find a common interface with which to access any of these members, to generalise the following MVC3 controller code into one controller:
public ActionResult Edit(DropDownListModel model, Guid)
{
var dbSet = _dbContext.Countries;
var newItems = model.Items.Where(i => i.IsNew && !i.IsDeleted).Select(i => new { i.Name });
foreach (var item in newItems)
{
if (!string.IsNullOrWhiteSpace(item.Name))
{
var undead = ((IEnumerable<IdNamePairBase>)dbSet).FirstOrDefault(p => p.Name.ToLower() == item.Name.ToLower());
if (undead != null)
{
// Assign new value to update to the new char. case if present.
undead.Name = item.Name;
undead.IsDeleted = false;
_dbContext.SaveChanges();
continue;
}
var newPair = new Country { Name = item.Name };
dbSet.Add(newPair);
_dbContext.SaveChanges();
}
}
return RedirectToAction("Edit", new {listName = model.ListName});
}
How could I go about resolving my problem that right now I need one controller for each of the DbContext members, like the one above is dedicated to DbSet<Country> Countries?
PARTIAL SOLUTION: Along lines similar to GertArnold's answer below, before I knew about the _dbContext.Set<T> all he highlights, I implemented this method on my context class to get sets of a specific type:
public IEnumerable<DbSet<T>> GetDbSetsByType<T>() where T : class
{
//var flags = BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance;
var props = GetType().GetProperties()
.Where(p => p.PropertyType.IsGenericType && p.PropertyType.Name.StartsWith("DbSet"))
.Where(p => p.PropertyType.GetGenericArguments().All(t => t == typeof(T)));
return props.Select(p => (DbSet<T>)p.GetValue(this, null));
}
Some generalization is possible by using
var dbSet = _dbContext.Set<T>
and putting most of your method in a method with a generics type parameter.
However, there should be a switch somewhere to decide which type should be specified and which type to create, because I think the type is supplied as a property of the model (is it?). So it probably won't really look elegant, but probably be a lot shorter, with DRY-er code.
To add on Gert Arnold's answer, I want to note that there is another method overload on the dbContext that returns a general DbSet from a type object:
var dbSet = dbContext.Set(typeof(T))
If you want to add blind an object, then create the object using the set.Create() method, or if you already have an object created with the "new" keyowrd, you can convert it by using (similar to this answer)
var entity = dbSet.Create();
dbSet.Add(entity);
DbEntityEntry entry = context.Entry(entity);
entry.CurrentValues.SetValues(yourObject);
I've been looking for an answer to this question and I've found that it is easy to do using the Managed Extensibility Framework. There is a quicker way at the bottom of this post, however MEF allows for a much more scalable approach.
MEF allows you to build dynamic access plugins from disparate Assemblies; however it can be used to quickly populate Collections within a single assembly application.In essence, we'll be using it as a safe way of reflecting our assembly back into the class. In order to make this fully functional, I'm also going to implement the Strategy Pattern to the Entity Framework Model.
Add a reference to your project, pointing to System.ComponentModel.Composition. This will give access to the MEF library.
Now, we need to implement the Strategy Pattern. If you don't have an Interfaces folder, create one, and add IEntity.cs, as below.
IEntity.cs
namespace Your.Project.Interfaces
{
/// <summary>
/// Represents an entity used with Entity Framework Code First.
/// </summary>
public interface IEntity
{
/// <summary>
/// Gets or sets the identifier.
/// </summary>
/// <value>
/// The identifier.
/// </value>
int Id { get; set; }
}
}
Now, each of you concrete entities need to implement this Interface:
public class MyEntity : IEntity
{
#region Implementation of IEntity
/// <summary>
/// Gets or sets the identifier.
/// </summary>
/// <value>
/// The identifier.
/// </value>
public int Id { get; set; }
#endregion
// Other POCO properties...
}
I find that it is best practice, not to create individual interfaces for each entity, unless you're working in a high testing environment. Pragmatically, interfaces should only be used where that level of abstraction is needed; mainly when more than one concrete class will inherit, or when working with an over-enthusiastic Inversion of Control engine. If you have interfaces for everything in your production model, your architecture more than likely, has major flaws. Anyway, enough of the rambling.
Now that we have all of our entities "strategised", we can use MEF to collate them and populate a collection within your context.
Within your context, add a new property:
/// <summary>
/// Gets a dynamically populated list of DbSets within the context.
/// </summary>
/// <value>
/// A dynamically populated list of DbSets within the context.
/// </value>
[ImportMany(typeof(DbSet<IEntity>))]
public IEnumerable<DbSet<IEntity>> Sets { get; private set; }
The [ImportMany(typeof(DbSet<IEntity>))] here, allows MEF to populate the collection.
Next, add the corresponding Export attribute to each DbSet within the context:
[Export(typeof(DbSet<IEntity>))]
public DbSet<MyEntity> MyEntities { get; set; }
Each of the Imported and Exported properties is known as a "part". The final piece to the puzzle is to compose those parts. Add the following to your context's constructor:
// Instantiate the Sets list.
Sets = new List<DbSet<IEntity>>();
// Create a new Types catalogue, to hold the exported parts.
var catalogue = new TypeCatalog(typeof (DbSet<IEntity>));
// Create a new Composition Container, to match all the importable and imported parts.
var container = new CompositionContainer(catalogue);
// Compose the exported and imported parts for this class.
container.ComposeParts(this);
Now, with any luck, you should have a dynamically populated list of DbSets, within your context.
I have used this method to allow easy truncating of all tables via an extension method.
/// <summary>
/// Provides extension methods for DbSet objects.
/// </summary>
public static class DbSetEx
{
/// <summary>
/// Truncates the specified set.
/// </summary>
/// <typeparam name="TEntity">The type of the entity.</typeparam>
/// <param name="set">The set.</param>
/// <returns>The truncated set.</returns>
public static DbSet<TEntity> Truncate<TEntity>(this DbSet<TEntity> set)
where TEntity : class, IEntity
{
set.ToList().ForEach(p => set.Remove(p));
return set;
}
}
I have added a method to the context to truncate the whole database.
/// <summary>
/// Truncates the database.
/// </summary>
public void TruncateDatabase()
{
Sets.ToList().ForEach(s => s.Truncate());
SaveChanges();
}
EDIT (Overhaul):
The solution above has now been depreciated. Some tweeking as had to be done to get this to work now. To make this work, you need to import the DbSets into a temporary collection of DbSet of type "object", then cast this collection to DbSet of your required interface type. For basic purposes, the IEntity interface will suffice.
#region Dynamic Table List
/// <summary>
/// Gets a dynamically populated list of DbSets within the context.
/// </summary>
/// <value>
/// A dynamically populated list of DbSets within the context.
/// </value>
public List<DbSet<IEntity>> Tables { get; private set; }
/// <summary>
/// Gets a dynamically populated list of DbSets within the context.
/// </summary>
/// <value>
/// A dynamically populated list of DbSets within the context.
/// </value>
[ImportMany("Sets", typeof (DbSet<object>), AllowRecomposition = true)]
private List<object> TableObjects { get; set; }
/// <summary>
/// Composes the sets list.
/// </summary>
/// <remarks>
/// To make this work, you need to import the DbSets into a temporary collection of
/// DbSet of type "object", then cast this collection to DbSet of your required
/// interface type. For basic purposes, the IEntity interface will suffice.
/// </remarks>
private void ComposeSetsList()
{
// Instantiate the list of tables.
Tables = new List<DbSet<IEntity>>();
// Instantiate the MEF Import collection.
TableObjects = new List<object>();
// Create a new Types catalogue, to hold the exported parts.
var catalogue = new TypeCatalog(typeof (DbSet<object>));
// Create a new Composition Container, to match all the importable and imported parts.
var container = new CompositionContainer(catalogue);
// Compose the exported and imported parts for this class.
container.ComposeParts(this);
// Safe cast each DbSet<object> to the public list as DbSet<IEntity>.
TableObjects.ForEach(p => Tables.Add(p as DbSet<IEntity>));
}
#endregion
Next, run the CompileSetsList() facade from the constructor (with best practices for Web shown):
public MvcApplicationContext()
{
// Enable verification of transactions for ExecuteSQL functions.
Configuration.EnsureTransactionsForFunctionsAndCommands = true;
// Disable lazy loading.
Configuration.LazyLoadingEnabled = false;
// Enable tracing of SQL queries.
Database.Log = msg => Trace.WriteLine(msg);
// Use MEF to compile a list of all sets within the context.
ComposeSetsList();
}
Then, just decorate your DbSet<>s like this:
/// <summary>
/// Gets or sets the job levels.
/// </summary>
/// <value>
/// The job levels.
/// </value>
[Export("Sets", typeof(DbSet<object>))]
public DbSet<JobLevel> JobLevels { get; set; }
Now it will work properly.

Categories

Resources