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.
I created Xamarin.Forms Windows UWP and Android application with shared project.
To both(UWP and Android) I imported latest stable NuGet packages:
Microsoft.EntityFramework version 1.0.0, Microsoft.EntityFramework.Sqlite version 1.0.0 and Xamarin.Forms 2.3.1.114.
On shared project I created very simple data model:
public class User
{
public int Id { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public string Notes { get; set; }
}
and very simple data context:
public class DataDbContext: DbContext
{
public static string DatabasePathName;
public DataDbContext()
: base()
{
}
public DataDbContext(DbContextOptions options)
: base(options)
{
}
public DbSet<User> Users { get; set; }
protected override void OnConfiguring(
DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlite(
String.Format("Filename={0}", DataDbContext.DatabasePathName));
base.OnConfiguring(optionsBuilder);
}
}
(The model uses, according to docs.efproject.net, an implicit definition of the field Id as the key and autoincrement.)
Now I initialize database: First set the platform dependent property DatabasePathName and second I'll add three User items to each. I assume that the values of these records will later be read from Resources. At this point, it is just I enter as literals. Records are saved by SaveChanges() method(both UWP and Android returns 3 (saved records)).
Now, if I run Windows UWP application and retrive these records by:
List<User> users = dbContext.Users.ToList();
and everything is as it should be. I read the records, so do I get a value which I put in a TextBlock control.
But if I use the same code in Xamarin Android Application, this code throws System.NotImplementedException exception.
I don't know why. Thank you for the advice.
There are still a few known issues with Xamarin's implementation of the .NET Standard. See aspnet/Microsoft.Data.Sqlite#255 for more details. We'll keep that issue up-to-date as Xamarin lights up.
I'm using the new MVC6 framework with Visual Studio 2015, and suddenly all my Data Annotations stopped working. All of them, without me changing the code.
public sealed class RegisterUser
{
[Required(ErrorMessage = "required")]
[RegularExpression(#"^((.|\n)*)$", ErrorMessage = "regex")]
[StringLength(32, MinimumLength = 3, ErrorMessage = "length")]
public string Name { get; set; }
...
}
And
[Route(Address + "/membership")]
public class MembershipController : Controller
{
// POST [address]/membership/register
[AllowAnonymous]
[HttpPost("Register")]
public IActionResult Register([FromBody]RegisterUser model)
{
// Validate the input model.
if (model == null)
return ...
if (!ModelState.IsValid)
return ...
// Always get HERE
}
}
Why, on earth, do I pass the "ModelState.IsValid" test (it always evaluates to true) ?
For example, I'm passing Name="x", and it still evaluates to true. As if the annotations aren't there.
Does it relate to using MvcCore ?
Frustrating as it is, I forgot that changing to 'core' project strips out many of the common features. And so, in Startup.cs, add
services.AddMvc()
or
services.AddMvcCore().AddDataAnnotations()
Depending on your usage.
Was experiencing the same issue and commented this following line of code
services.AddControllersWithViews(options => {
// options.ModelValidatorProviders.Clear();
}).AddRazorRuntimeCompilation();
I don't remember why I added this line of code...
{ get; set; } Required
I know the OP has NOT made this error but I have just wasted a number of hours...
Need to use public string Name { get; set; } and not public string Name;
I'm using ASP Core 3.1.
I am creating an Xamarin.iOS app and a Realm database.I would like to keep my POCO objects separate from my RealmObject so what I did was use a repository pattern and within the repository I tried to use AutoMapper to map the POCO to the RealmObject
e.g. (subset)
public class PlaceRepository : IPlaceRepository
{
private Realm _realm;
public PlaceRepository(RealmConfiguration config)
{
_realm = Realm.GetInstance(config);
}
public void Add(Place place)
{
using (var trans = _realm.BeginWrite())
{
var placeRealm = _realm.CreateObject<PlaceRealm>();
placeRealm = Mapper.Map<Place, PlaceRealm>(place);
trans.Commit();
}
}
So, if I debug my code everything maps OK and placeRealm is populated OK but when I commit nothing gets saved to the Realm db. The following is my RealmObject
public class PlaceRealm : RealmObject
{
[ObjectId]
public string Guid { get; set; }
public string Title { get; set; }
public string Notes { get; set; }
}
and this is my POCO Place
public class Place
{
public string Guid { get; set; }
public string Title { get; set; }
public string Notes { get; set; }
}
And AutoMapper is initialized like so:
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Place, PlaceRealm>();
cfg.CreateMap<PlaceRealm, Place>();
});
All standard stuff. Has anyone else managed to get something similar working?
Your poco 'Place' is called 'PlaceRealm'. I suspect that is a typo. (made edit)
I suspect that Automapper is instantiating a new object overwriting your original 'placeRealm' object.
Perhaps you could try
Mapper.Map(place, placeRealm);
in place of your current mapping.
which should just copy the values to your already instatiated and tracked object.
(no need to store the return value).
You might also want to make explicit which properties (3) you are mapping as currently Automapper will map all including those in the base class.
On a side note, you may run into performance issues with Automapper. I found it to be the performance bottleneck in some apps. ExpressMapper is a nice alternative.
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.