OnCascadeDelete and Entity Framework - asp.net-mvc-3

I have a company model:
public class Company
{
public int Id { get; set; }
...
public virtual ICollection<Useraccount> Useraccounts { get; set; }
}
And a useraccount model:
public class Useraccount
{
public int Id { get; set; }
...
public virtual ICollection<Company> Companies { get; set; }
}
So it's a m:n connection:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
modelBuilder.Entity<Company>()
.HasMany(c => c.Useraccounts).WithMany(i => i.Companies)
.Map(t => t.MapLeftKey("CompanyId")
.MapRightKey("UseraccountId")
.ToTable("UseraccountCompany"));
}
However an exception is thrown when initializing the database.
With
modelBuilder.Conventions.Remove<OneToManyCascadeDeleteConvention>();
the initialization is working.
I'd like to keep the cascade on delete but I'm not sure how to manage it.
I also would like to keep both virtual properties so I can access the useraccounts from a company and the companies from the useraccount.
The exception btw is:
Introducing FOREIGN KEY constraint 'Company_Useraccounts_Target' on table
'UseraccountCompany' may cause cycles or multiple cascade paths.
Specify ON DELETE NO ACTION or ON UPDATE NO ACTION, or modify
other FOREIGN KEY constraints.Could not create constraint.

That should work (you probably haven't posted some relevant bits in your model - fluent configuration).
That usually appears when you have some 'self-referencing' entities
(either directly or indirectly) - but I don't see that here, this is
typical many-to-many.
But if problems persist you can always implement the join table yourself - with more control over cascading - and that usually solves the problems (if possible).
I hate to retype :) - here is almost the exact problem - with many-to-many manually done (part-2).
EF5 And cycles or multiple cascade paths, FOREIGN KEY
Take a look and see if it helps.

Related

EF Core 5 Duplicating Records in the Many-to-Many Relationship

I'm having trouble implementing the many-to-many relationship using the Entity Framework Core 5 in Visual Studio.
I have the classes:
public class Medico
{
public Medico()
{
this.Especialidades = new HashSet<Especialidade>().ToList();
}
public int Id { get; set; }
public string Nome { get; set; }
public int CRM { get; set; }
public List<Especialidade>Especialidades { get; set; }
public class Especialidade
{
public int Id { get; set; }
public string Descricao { get; set; }
public IList<Medico>Medicos { get; set; }
}
And the Create method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Nome,CRM")] Medico medico)
{
var lstTags = Request.Form["chkTags"];
if (!string.IsNullOrEmpty(lstTags))
{
int[] splTags = lstTags.ToString().Split(',').Select(Int32.Parse).ToArray();
if (splTags.Count() > 0)
{
var medicoEspecialidades = await _context.Especialidades.Where(t => splTags.Contains(t.Id)).ToListAsync();
foreach (var me in medicoEspecialidades)
{
medico.Especialidades.Add(me);
}
}
}
if (ModelState.IsValid)
{
_context.Medicos.Add(medico);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
return View(medico);
}
But when I run Create, it returns me with the following error:
"Cannot insert explicit value for identity column in table 'Especialidades' when IDENTITY_INSERT is set to OFF."
If I turn off the Identity_Insert of the Specialty table in the bank, it even inserts, but duplicates the records in the Specialty table.
I've been researching and trying to find a solution for 2 days now. Can someone who has been through this give me a hand?
The application source code is here: https://www.dropbox.com/s/xn6b95h7amfpuqa/AppCompleta%205.0.rar?dl=1
The approach looks Ok, though I would check to ensure that the medico being passed in does not have any Especialidade somehow coming in from the client as these would be detached entities. The error seems to imply that Medico may have a detached Especialidade in its collection. If the checked values represents everything that should be tracked, then this collection should be cleared and the Especialidade references added.
Do you have any explicit mapping configuration for either of these entities? If not I would highly recommend using one for Many-to-Many relationships as sometimes EF can default to unexpected schema assumptions when working off convention, especially in Code First if that is the case. I would look at your schema carefully to ensure it is matching what would be expected for a Many-To-Many. For example, what is the linking table name for Medico-Especialidade? Is there an entity defined for it in the configuration? This is entirely optional and EF should work it out, however if you do have explicit mapping that might not be configured correctly, tripping up the relationships.
One other detail giving off a smell:
public Medico()
{
this.Especialidades = new HashSet<Especialidade>().ToList();
}
public List<Especialidade>Especialidades { get; set; }
This should be:
public ICollection<Especialidade> { get; set; } = new HashSet<Especialidade>();
EF can work with lists, but when it comes to proxies and the behind the scenes EF is doing with entities it is generally better to declare your collection references as ICollection rather than concrete classes. ToListing a HashSet merely produces a List, so either = new HashSet<Especialidade>() or = new List<Especialidade>() will do. The difference would merely be the behaviour of the collection when you are populating it after "newing" up a Medico, or deserializing one.

Additional column in query generated by Entity Framework

I am using EF5 and .NET 4.5 targeting an Oracle 11g database through Oracle.ManagedDataAccess.Client. I set up a small table to test and the how it works.
Now here is a weird fact which shows no result on searching the web nor this site. On every query I have a last column like "Extent1"."Text_TextID"!!! This obviously makes Oracle to throw an error Invalid identifier as I have no column with such name nor another object in the database.
This happens no matter how many tables/columns I have and no matter how I name them (if I have several tables all will have this extra column in the query).
Anybody has any idea why this happens??
Sample code below:
//POCO class and mapping
[Table("LO_USERS")]
public class User
{
[Key]
[Column("USER_ID")]
public int UserID { get; set; }
}
//define the context
public class TestContext : DbContext
{
public TestContext():base("OracleConn")
{
}
public DbSet<User> Users { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
//replace the annoying dbo schema name. Note: even if I remove this, I still get the extra column in the query
modelBuilder.Entity<User>().ToTable("LO_USERS", "TEST_SCHEMA");
}
//create a new user
using (var db = new TestContext())
{
var user = new User();
db.Users.Add(user);
//here I set a breakpoint
db.SaveChanges();
}
The query as showing by VS2012 at the breakpoint:
SELECT
1 AS "C1",
CAST( "Extent1"."USER_ID" AS number(10,0)) AS "C2",
"Extent1"."Text_TextID" AS "Text_TextID"
FROM "TEST_SCHEMA"."LO_USERS" "Extent1"
Edit:
It is the same with EF6 and DotConnect.
I found it: the problem was I was referencing User class in another class as child object, like
public class Text
{
public virtual ICollection<User> Users { get; set; }
without specifying any foreign key column in user class and EF was trying to set one by its own.
Once I removed the line above the extra column disappeared from the select statement.

Entity Framework CodeFirst KeyNotFoundException in MemberDomainMap

Trying to run down an error in my EF datacontext implementation that is yielding a fairly cryptic error.
Test Name: Nodes_can_be_saved
Test FullName: MyProj.Test.Integration.AFDataContextTest.Nodes_can_be_saved
Test Source: c:\Users\pvencill. \Documents\Visual Studio 2012\Projects\MyProj\MyProj.Test\Integration\AFDataContextTest.cs : line 49
Test Outcome: Failed
Test Duration: 0:00:01.4192808
Result Message:
Test method MyProj.Test.Integration.AFDataContextTest.Nodes_can_be_saved threw exception:
System.Data.Entity.Infrastructure.DbUpdateException: Error retrieving values from ObjectStateEntry. See inner exception for details. ---> System.Data.UpdateException: Error retrieving values from ObjectStateEntry. See inner exception for details. ---> System.Collections.Generic.KeyNotFoundException: The given key was not present in the dictionary.
Result StackTrace:
at System.Collections.Generic.Dictionary`2.get_Item(TKey key)
at System.Data.Mapping.ViewGeneration.Structures.MemberDomainMap.GetDomainInternal(MemberPath path)
at System.Data.Mapping.ViewGeneration.QueryRewriting.FragmentQueryKB.CreateIsOfTypeCondition(MemberPath currentPath, IEnumerable`1 derivedTypes, MemberDomainMap domainMap)
at System.Data.Mapping.ViewGeneration.QueryRewriting.FragmentQueryKB.CreateVariableConstraintsRecursion(EdmType edmType, MemberPath currentPath, MemberDomainMap domainMap, EdmItemCollection edmItemCollection)
at System.Data.Mapping.ViewGeneration.QueryRewriting.FragmentQueryKB.CreateVariableConstraintsRecursion(EdmType edmType, MemberPath currentPath, MemberDomainMap domainMap, EdmItemCollection edmItemCollection)
at System.Data.Mapping.ViewGeneration.ViewgenContext..ctor(ViewTarget viewTarget, EntitySetBase extent, IEnumerable`1 extentCells, CqlIdentifiers identifiers, ConfigViewGenerator config, MemberDomainMap queryDomainMap, MemberDomainMap updateDomainMap, StorageEntityContainerMapping entityContainerMapping)
at System.Data.Mapping.ViewGeneration.ViewGenerator.CreateViewgenContext(EntitySetBase extent, ViewTarget viewTarget, CqlIdentifiers identifiers)
at System.Data.Mapping.ViewGeneration.ViewGenerator.GenerateDirectionalViewsForExtent(ViewTarget viewTarget, EntitySetBase extent, CqlIdentifiers identifiers, KeyToListMap`2 views)
at System.Data.Mapping.ViewGeneration.ViewGenerator.GenerateDirectionalViews(ViewTarget viewTarget, CqlIdentifiers identifiers, KeyToListMap`2 views)
at System.Data.Mapping.ViewGeneration.ViewGenerator.GenerateAllBidirectionalViews(KeyToListMap`2 views, CqlIdentifiers identifiers)
at System.Data.Mapping.ViewGeneration.ViewgenGatekeeper.GenerateViewsFromCells(List`1 cells, ConfigViewGenerator config, CqlIdentifiers identifiers, StorageEntityContainerMapping containerMapping)
at System.Data.Mapping.ViewGeneration.ViewgenGatekeeper.GenerateViewsFromMapping(StorageEntityContainerMapping containerMapping, ConfigViewGenerator config)
at System.Data.Mapping.StorageMappingItemCollection.ViewDictionary.SerializedGenerateViews(StorageEntityContainerMapping entityContainerMap, Dictionary`2 resultDictionary)
at System.Data.Mapping.StorageMappingItemCollection.ViewDictionary.SerializedGetGeneratedViews(EntityContainer container)
at System.Data.Common.Utils.Memoizer`2.<>c__DisplayClass2.<Evaluate>b__0()
at System.Data.Common.Utils.Memoizer`2.Result.GetValue()
at System.Data.Common.Utils.Memoizer`2.Evaluate(TArg arg)
at System.Data.Mapping.StorageMappingItemCollection.ViewDictionary.GetGeneratedView(EntitySetBase extent, MetadataWorkspace workspace, StorageMappingItemCollection storageMappingItemCollection)
at System.Data.Mapping.Update.Internal.ViewLoader.InitializeEntitySet(EntitySetBase entitySetBase, MetadataWorkspace workspace)
at System.Data.Mapping.Update.Internal.ViewLoader.SyncInitializeEntitySet[TArg,TResult](EntitySetBase entitySetBase, MetadataWorkspace workspace, Func`2 evaluate, TArg arg)
at System.Data.Mapping.Update.Internal.ViewLoader.SyncContains[T_Element](EntitySetBase entitySetBase, MetadataWorkspace workspace, Set`1 set, T_Element element)
at System.Data.Mapping.Update.Internal.ExtractorMetadata..ctor(EntitySetBase entitySetBase, StructuralType type, UpdateTranslator translator)
at System.Data.Mapping.Update.Internal.UpdateTranslator.GetExtractorMetadata(EntitySetBase entitySetBase, StructuralType type)
at System.Data.Mapping.Update.Internal.ExtractorMetadata.ExtractResultFromRecord(IEntityStateEntry stateEntry, Boolean isModified, IExtendedDataRecord record, Boolean useCurrentValues, UpdateTranslator translator, ModifiedPropertiesBehavior modifiedPropertiesBehavior)
at System.Data.Mapping.Update.Internal.RecordConverter.ConvertStateEntryToPropagatorResult(IEntityStateEntry stateEntry, Boolean useCurrentValues, ModifiedPropertiesBehavior modifiedPropertiesBehavior)
--- End of inner exception stack trace ---
at System.Data.Mapping.Update.Internal.RecordConverter.ConvertStateEntryToPropagatorResult(IEntityStateEntry stateEntry, Boolean useCurrentValues, ModifiedPropertiesBehavior modifiedPropertiesBehavior)
at System.Data.Mapping.Update.Internal.ExtractedStateEntry..ctor(UpdateTranslator translator, IEntityStateEntry stateEntry)
at System.Data.Mapping.Update.Internal.UpdateTranslator.LoadStateEntry(IEntityStateEntry stateEntry)
at System.Data.Mapping.Update.Internal.UpdateTranslator.PullModifiedEntriesFromStateManager()
at System.Data.Mapping.Update.Internal.UpdateTranslator.ProduceCommands()
at System.Data.Mapping.Update.Internal.UpdateTranslator.Update(IEntityStateManager stateManager, IEntityAdapter adapter)
at System.Data.EntityClient.EntityAdapter.Update(IEntityStateManager entityCache)
at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
at System.Data.Entity.Internal.InternalContext.SaveChanges()
--- End of inner exception stack trace ---
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at MyProj.Data.MyProjDataContext.SaveChanges() in c:\Users\pvencill. \Documents\Visual Studio 2012\Projects\MyProj\MyProj.Data\MyProjDataContext.cs:line 44
at MyProj.Test.Integration.AFDataContextTest.Nodes_can_be_saved() in c:\Users\pvencill. \Documents\Visual Studio 2012\Projects\MyProj\MyProj.Test\Integration\AFDataContextTest.cs:line 55
Researching the error led to few hits on Google, but the ones I found suggested that it's something to do w/ my model relationships, though in looking at the DB that the migrations generated, all seems in order to my eyes. My relevant models are as follows:
My data context DBSets and modelCreating definition:
public DbSet<Blip> Blips { get; set; }
public DbSet<SensorAdapter> Sensors { get; set; }
public DbSet<NodeReport> NodeReports { get; set; }
public DbSet<Node> Nodes { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<Blip>().Property(b => b.TimeStamp).HasColumnType("datetime2");
modelBuilder.Entity<Node>().HasMany<NodeReport>(n => n.NodeReports).WithRequired(nr=>nr.Node);
modelBuilder.Entity<Blip>().HasMany<NodeReport>(b => b.NodeReports);
base.OnModelCreating(modelBuilder);
}
The Blips and SensorAdapter objects worked fine prior to adding NodeReports to them, so I suspect it's in there that the project lies.
I have a base Entity object that all my stuff inherits from, which just defines an Id property of type T; that was working fine.
NodeReport inherits from Report, whose definition is here:
public abstract class Report : Entity<long>
{
public Report()
{
Status = Status.Unknown;
}
public DateTime TimeStamp { get; set; }
public Status Status { get; set; }
public String Raw { get; set; }
}
NodeReport in turn is defined thus:
public class NodeReport : Report
{
public virtual Node Node { get; set; }
//public virtual Blip Blip { get; set; }
}
I tried it both with and without the Blip on there, commented out at the moment as I try and narrow down the problem
A Node is a fairly sparse class at hte moment too:
public class Node : Entity<long>
{
public Node ()
{
NodeReports = new List<NodeReport>();
}
public String HostName { get;set; }
public String Description { get; set; }
public virtual IList<NodeReport> NodeReports { get; set; }
}
Any suggestions would be greatly appreciated, I've been beating myself up trying to figure it.
Well, after much searching through my code and rebuilding from scratch I found that the problem was actually that I had a derived class of Node that had a Uri as a property, which obviously failed mapping since it doesn't have a default constructor (and possibly other reasons). I solved it for now by simply changing the property to a String which I validate as a Uri internally, though I would have preferred a more elegant solution. I tried mapping Uri and even a custom subclass (w/ default constructor) of Uri to a complextype, but that didn't help.
Still, the question above is answered.
With the #Paul's answer I could finally figure out my problem.
I am using EF with Inheritance TPT (Table per Type).
The source code
To make it easier I'll use the same classes discribed in this tutorial.
public abstract class BillingDetail
{
public int BillingDetailId { get; set; }
public string Owner { get; set; }
public string Number { get; set; }
}
[Table("BankAccounts")]
public class BankAccount : BillingDetail
{
public string BankName { get; set; }
public string Swift { get; set; }
public Agency Agency { get; set; } /* I added it */
}
public class InheritanceMappingContext : DbContext
{
public DbSet<BillingDetail> BillingDetails { get; set; }
}
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<BankAccount>().ToTable("BankAccounts");
modelBuilder.Entity<CreditCard>().ToTable("CreditCards");
}
The problem
Note that I've added a new property called Agency inside the BankAccount. Given it is a complex type, if you do not map it you'll get this annoying error at runtime!
Solution
What I did was simply ignore this property Agency, but you can also map it to EF know what to do. Both will stop the error.
The most weird thing is that even not mapping the derived entity (BankAccount) the problem occurs. It seems that EF somehow knows that you created the derivation. So, if you're trying to run EF without mapping some derivation you will probably get this error too.
I have the same issue, unfortunately none of the solutions here in StackOverflow worked for me aside from the answers on other questions related to this issue.
But I found my own fix and you can also check it in your part if you have the same issue as mine. What happen is that if some class inherits from the table that I am using on my DbSet:
public DbSet<Employee> Employees { get; set; }
On this case, if some other classes inherit from my POCO Employee, this triggers this particular error. I removed all inheritance from this class and this fixes the issue.
Take note that this inheritance issue which triggers this same issue:
The given key was not present in the dictionary.
Only happens if the inheritance is on the same project. I tried to inherit the POCO on different project and it happens to be fine.

How to assign my models to built-in users

I am trying to implement a foreign key connection between the built-in User model and my models in ASP.NET MVC 3.
How to assign ownership or some other roles to various entries represented with my models. Example of how my models look like:
public class Entry
{
public int Id { get; set; }
public string Value { get; set; }
public User Owner { get; set; }
public User SomeoneElse { get; set; }
}
Where to find the model for users, what do I need to import? Or is there a better approach to accomplish this?
Do you use Entity Framework ?? If so...
Simple solution
You could simply keep the Guid from the Built-In User model. You won't have a "real relationship" but it will do the trick for what you want to do. You can always get the UserId with Membership.GetUser().ProviderUserKey
Other more complex
Completely rewrite and override the MembershipProvider and login module. That way you can use your own User object and add other properties to it aswell.
Not Sure about this one
Not sure if this one will work with the auto generated tables from the MembershipProvider but you can add the Foreign Key Property this way:
[ForeignKey("User")]
public Guid UserId { get; set; }

code first approach error: The specified type member 'xxxxx' is not supported in LINQ to Entities

In an effort to further abstract my repository layer I have attempted to follow the code-first approach as described here: http://msdn.microsoft.com/en-us/magazine/ee236639.aspx.
I have a many-to-many relationship between Account and Subscription entities. A Navigation property exists on each entity pointing to the other (e.g. Account.Subscriptions).
Before I created my own model I was using the Entity generated model and the below worked fine ("db" is the entity context) :
public IQueryable<Account> GetBySubscriptionId(int subId)
{
return from a in db.Accounts
where a.Subscriptions.Any(s => s.SubscriptionId == subId)
select a;
}
Now the model for Account looks like this:
public class Account
{
public int AccountId { get; set; }
public string Name { get; set; }
// nav properties
public virtual List<Subscription> Subscriptions { get; set; }
}
And when I try to run the same LINQ query now I get this error:
"The specified type member
'Subscriptions' is not supported in
LINQ to Entities. Only initializers,
entity members, and entity navigation
properties are supported."
Any suggestions greatly appreciated.
Try changing the signature from
// nav properties
public virtual List<Subscription> Subscriptions { get; set; }
to
// nav properties
public virtual ICollection<Subscription> Subscriptions { get; set; }
Shamelessly nicked from Scott Hanselmann's demo here - http://www.hanselman.com/blog/SimpleCodeFirstWithEntityFramework4MagicUnicornFeatureCTP4.aspx which uses this pattern, also here's a Scott Guthrie demo using the same idea http://weblogs.asp.net/scottgu/archive/2010/07/23/entity-framework-4-code-first-custom-database-schema-mapping.aspx .
List<T> is a concrete implementation of various interfaces (ICollection, IQueryable, IEnumerable etc), Entity Framework uses proxy objects when it retrieves things from the database, hence the virtual declarations, which use different implementations of these interfaces which is where your error is coming from.

Resources