I am trying to build one to many relationship between AspnetUsers and Trip.
My Trip class is as given below:
public class Trip
{
public int TripId { get; set; }
public string TripName { get; set; }
public string ApplicationUserId { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
}
I have added following in IdentityModel:
public virtual ICollection<Trip> Trips {get; set; }
Now when I try to run this or update-database I get the following error:
System.InvalidOperationException: Multiple object sets per type are not supported. The object sets 'ApplicationUsers' and 'Users' can both contain instances of type 'IdentityRelationship.Models.ApplicationUser'
at System.Data.Entity.Internal.DbSetDiscoveryService.RegisterSets(DbModelBuilder modelBuilder)
at System.Data.Entity.Internal.LazyInternalContext.CreateModelBuilder()
at System.Data.Entity.Internal.LazyInternalContext.CreateModel(LazyInternalContext internalContext)
at System.Data.Entity.Internal.RetryLazy`2.GetValue(TInput input)
at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()
at System.Data.Entity.Internal.LazyInternalContext.get_ModelBeingInitialized()
at System.Data.Entity.Infrastructure.EdmxWriter.WriteEdmx(DbContext context, XmlWriter writer)
at System.Data.Entity.Utilities.DbContextExtensions.<>c__DisplayClass1.<GetModel>b__0(XmlWriter w)
at System.Data.Entity.Utilities.DbContextExtensions.GetModel(Action`1 writeXml)
at System.Data.Entity.Utilities.DbContextExtensions.GetModel(DbContext context)
at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration, DbContext usersContext, DatabaseExistenceState existenceState, Boolean calledByCreateDatabase)
at System.Data.Entity.Migrations.DbMigrator..ctor(DbMigrationsConfiguration configuration)
at System.Data.Entity.Migrations.Design.MigrationScaffolder..ctor(DbMigrationsConfiguration migrationsConfiguration)
at System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldRunner.Run()
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.AppDomain.DoCallBack(CrossAppDomainDelegate callBackDelegate)
at System.Data.Entity.Migrations.Design.ToolingFacade.Run(BaseRunner runner)
at System.Data.Entity.Migrations.Design.ToolingFacade.ScaffoldInitialCreate(String language, String rootNamespace)
at System.Data.Entity.Migrations.EnableMigrationsCommand.<>c__DisplayClass2.<.ctor>b__0()
at System.Data.Entity.Migrations.MigrationsDomainCommand.Execute(Action command)
Multiple object sets per type are not supported. The object sets 'ApplicationUsers' and 'Users' can both contain instances of type 'IdentityRelationship.Models.ApplicationUser'.
Can anyone please tell me what's going on and how to solve this?
In my opinion class called Trip, should contains IdentityModel's foreign key virtual property (navigation property).
Fore example:
public class Trip{
public int TripId { get; set; }
public string TripName { get; set; }
public string ApplicationUserId { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
public int IdentityModelId{ get; set; }
[ForeignKey("IdentityModelId")]
public virtual IdentityModel IdentityModel{get; set; }
}
And afther that it should be possible to populate the collection into Trips property at IdentityModel class.
Related
I'm trying to define (using data annotations, that's the project pattern, not using the fluent api) a one-to-one relationship but the navigation property (public virtual HolidayType HolidayType) is always null. The db table is creating the ForeignKey correctly using the annotation [ForeignKey("HolidayTypeId")].
Holiday Model
[Table("Holidays", Schema = "PTO")]
public class Holiday : EntityBase
{
...
public long HolidayTypeId { get; set; }
[ForeignKey("HolidayTypeId")]
public virtual HolidayType HolidayType { get; set; }
...
}
db FK constraint
ALTER TABLE [PTO].[Holidays] WITH CHECK ADD CONSTRAINT [FK_Holidays_HolidayTypes_HolidayTypeId] FOREIGN KEY([HolidayTypeId])
REFERENCES [PTO].[HolidayTypes] ([Id])
ON DELETE CASCADE
GO
Holiday Types Table
[Table("HolidayTypes", Schema = "PTO")]
public class HolidayType : EntityBase
{
[Required]
[MaxLength(200)]
public string Description { get; set; }
public bool IsActive { get; set; }
}
EntityBase
public class EntityBase
{
[Key]
public long Id { get; set; }
[Required]
[MaxLength(200)]
public string Name { get; set; }
public Guid CreatedByGuidId { get; set; }
public DateTime DateCreated { get; set; }
public Guid UpdatedByGuidId { get; set; }
public DateTime? DateUpdated { get; set; }
[Timestamp]
public byte[] RowVersion { get; set; }
}
Here's the repository call, the holidays are retrieved but they are missing the HolidayType property - always null. My understanding, using the ForeignKey annotation, the query does not need to have an .include statement. My understanding is obviously flawed so my next step is to try the include statement to verify. I'm hoping that an include statement doesn't require an addition db call if that is the answer to my issue.
public async Task<IEnumerable<T>> ListAsync(Expression<Func<T, bool>> predicate)
{
return await ApplicationDbContext.Set<T>().Where(predicate).ToListAsync();
}
Looks like the .Include statement is needed but it breaks my repository implementation so I need to rethink that.
This now hydrates the HolidayType:
public async Task<List<Holiday>> GetHolidaysByEmployerId(long employerId, int? year = null)
{
Expression<Func<Holiday, bool>> predicate = holiday => holiday.EmployerId == employerId;
var result = await ApplicationDbContext.Set<Holiday>().Where(predicate)
.Include(holiday => holiday.HolidayType)
.ToListAsync();
return result.ToList();
}
I want to map XML elements into my database table (using Entity Framework):
var xmlSerializer = new XmlSerializer(typeof(Participant), new XmlRootAttribute("participant"));
var participant = (Participant)xmlSerializer.Deserialize(new StringReader(content));
I have Participant table which I can access by
[XmlRoot("participant", Namespace = "")]
public partial class Participant
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Participant()
{
this.GroupParticipant = new HashSet<GroupParticipant>();
this.ParticipantAddress = new HashSet<ParticipantAddress>();
this.ParticipantPublisher = new HashSet<ParticipantPublisher>();
this.ParticipantJob = new HashSet<ParticipantJob>();
this.ParticipantProvider = new HashSet<ParticipantProvider>();
}
[XmlElement("firstName")]
public string FirstName { get; set; }
[XmlElement("lastName")]
public string LastName { get; set; }
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
//[XmlElement("address")]
//[XmlElement("address")]
//[XmlArray("HashSet<ParticipantAddress>"), XmlElement("address")]
//[XmlArrayItem("ICollection<ParticipantAddress>")]
//[XmlAttribute(DataType = "ICollection<ParticipantAddress>", AttributeName = "address")]
[XmlElement("address", typeof(List<ParticipantAddress>))]
public virtual ICollection<ParticipantAddress> ParticipantAddress { get; set; }
}
ParticipantAddress is ICollection:
[Serializable]
[XmlInclude(typeof(HashSet<ParticipantAddress>))]
public partial class ParticipantAddress
{
public int ParticipantAddressId { get; set; }
public int ParticipantId { get; set; }
[XmlElement("city")]
public string City { get; set; }
[XmlElement("state")]
public string State { get; set; }
[XmlElement("zipCode")]
public string ZipCode { get; set; }
public virtual Participant Participant { get; set; }
}
Exception says:
{"There was an error reflecting type 'x.Participant'."}
My inner Exception says:
{"Cannot serialize member 'xParticipant.ParticipantAddress' of type 'System.Collections.Generic.ICollection`1[[x.ParticipantAddress, APS.Data.BatchInterface, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]]', see inner exception for more details."}
I am reading XML by streamReader.
I have tried
[XMLArray]
Changing ICollection to List
make class serializable
Is there any other way to overcome this problem or any examples related to my question or any changes I need to implement in my code?
ICollection is not serializable.
- You can use DTO.
- You can change the collection type (i.e. with List<>) and with XML serialization attributes avoid circular references and/or disable lazy load (i.e. use eagerly load using Include method) or the risk is that you serialize the whole database.
You have this issue because of the virtual properties. You try to serialize a class which has a reference to another class, which has a reference to the first, class, which... endless loop.
If you want to serialize an entity, the best thing you can do is use a DTO class, which is a class used only to export your data. In these classes you can't have virtual properties, but what you can do is include the DTO objects of your ParticipantAddress.
The other thing you can try, if it isn't a necessity to serialize to XML, is use the Newtonsoft.Json package to serialize the entities. The package has some options to deal with navigational properties.
I have created a region and change ICollection<> to List<> because
ICollection is an interface and interfaces are not serializable.
But List<> is a class and this class implements all the below interfaces:
IList, ICollection, IList, ICollection, IReadOnlyList, IReadOnlyCollection, IEnumerable, IEnumerable.
I kept both Icollection as well as List and put [XmlIgnore] on ICollection.
[XmlRoot("participant", Namespace = "")]
public partial class Participant
{
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")]
public Participant()
{
this.GroupParticipantList = new List<GroupParticipant>();
this.ParticipantAddressList = new List<ParticipantAddress>();
this.ParticipantPublisherList = new List<ParticipantPublisher>();
this.ParticipantJobList = new List<ParticipantJob>();
this.ParticipantProviderList = new List<ParticipantProvider>();
}
[XmlElement("firstName")]
public string FirstName { get; set; }
[XmlElement("lastName")]
public string LastName { get; set; }
[XmlIgnore]
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")]
public virtual ICollection<ParticipantAddress> ParticipantAddress { get; set; }
#region Custom properties
[XmlElement("address")]
public virtual List<ParticipantAddress> ParticipantAddressList { get; set; }
#endregion
}
But with this option I am having another Problem: If I do any single change in my SQL database and if I do update model from database, then I lose manually implemented code like all the XML sentences in this code.
I answered this in the below article to add [System.Xml.Serialization.XmlIgnore] to entity.tt template
Prevent Property from being serialized
I had a similar issue using EF, to implement a Web service and couldn't serialize the ICollection<> object.
I hopes this helps you out.
public class User
{
public User()
{
sessions = new HashSet<Session>();
}
public int Id { get; set; }
public string Name { get; set; }
[XmlIgnore]
[IgnoreDataMember]
public virtual ICollection<Session> sessions { get; set; }
}
public class Session
{
public int Id { get; set; }
public Datetime start_dtime{ get; set; }
public Datetime end_dtime{ get; set; }
public virtual User user{ get; set; }
}
I have a class Ticket which has some properties. Three of these (View, Task and Key) properties are navigation properties. Those properties already exist in database even before a ticket has been stored. In my application I load those properties from the database first and then create a Ticket object. I need to save only the ticket (not the underlying objects ) to the database with the id to Key, View and Task (these are primery keys in the Ticket table)
[Table("Tickets")]
public class Ticket
{
[Key]
public int Id { get; set; }
public DateTime? Created { get; set; }
[Required]
public View View{ get; set; }
[Required]
public Key Key { get; set; }
public Task Task { get; set; }
}
I try to save the Ticket object like this:
db.Tickets.Add(ticket);
db.Entry(ticket.Key).State = System.Data.Entity.EntityState.Unchanged;
db.Entry(ticket.View).State = System.Data.Entity.EntityState.Unchanged;
db.Entry(ticket.Task).State = System.Data.Entity.EntityState.Unchanged;
db.SaveChanges();
When I try this approach I get the error:
{"Message":"An error has occurred.","ExceptionMessage":"Saving or accepting changes failed because more than one entity of type 'Key' have the same primary key value. Ensure that explicitly set primary key values are unique. Ensure that database-generated primary keys are configured correctly in the database and in the Entity Framework model. Use the Entity Designer for Database First/Model First configuration. Use the 'HasDatabaseGeneratedOption\" fluent API or 'DatabaseGeneratedAttribute' for Code First configuration.","
Is it even possible to work with Entity Framework this way? Having pre defined data which is loaded to it's objects (Key, View, Task) first and later assign these objects to an object having these properties but then in the entity framework context only adding the parent object, in this case the ticket?
I have also tried to set the underlying objects to null but then I will loose the data for those underlying objects, data I need later on in the application.
This is how the underlying objects look like:
[Table("Views")]
public class View
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Version { get; set; }
[Required]
public DateTime? Created { get; set; }
}
[Table("Keys")]
public class Key
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Version { get; set; }
[Required]
public DateTime? Created { get; set; }
}
[Table("Tasks")]
public class Task
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Version { get; set; }
[Required]
public DateTime? Created { get; set; }
}
Try adding Foreign Keys to your object and making those required instead of making the navigation property required. Like so:
[Table("Tickets")]
public class Ticket
{
[Key]
public int Id { get; set; }
public DateTime? Created { get; set; }
[Required]
public int ViewId {get; set; }
[ForeignKey("ViewId")]
public View View{ get; set; }
[Required]
public int KeyId {get; set; }
[ForeignKey("KeyId")]
public Key Key { get; set; }
public Task Task { get; set; }
}
I created one custom library project and it have Employee class to hold employee information.
namespace Test.SampleLib
{
public class Employee
{
public string EmployeeName { get; set; }
public double EmployeeSalary {get; set; }
}
}
I added the Employee class library to the WCF service
public Test.SampleLib.Employee GetDataUsingDataContract(Test.SampleLib.Employee composite)
{
return composite;
}
I tried to consume the service and access the method GetDataUsingDataContract()
ServiceReference1.Service1Client objServiceRef = new ServiceReference1.Service1Client();
Test.SampleLib.Employee objEmployee = new SampleLib.Employee();
objEmployee.EmployeeName = "Kumar";
objEmployee.EmployeeSalary = 30000;
objServiceRef.GetDataUsingDataContract(objEmployee); //Gives errror
The error is
'Argument 1: cannot convert from 'Test.SampleLib.Employee' to 'Test.Web.ServiceReference1.Employee'
You need to have [DataContract] and [DataMember] attributes on custom data types and its properties you want to expose.
[DataContract]
public class Employee
{
[DataMember]
public string EmployeeName { get; set; }
[DataMember]
public double EmployeeSalary {get; set; }
}
I have a SalesOrder table which inherits from a SalesDocument table using Table Per Type Inheritance
The ( simplified) table classes are;
[Table("SalesDocumentHeaders")]
public abstract class SalesDocumentHeader
{
[ForeignKey("CreatedByUserId")]
public virtual User CreatedBy { get; set; }
[Required]
public int CreatedByUserId { get; set; }
[Required]
public virtual DateTime? DocumentDate { get; set; }
[Required]
public String ReferenceNumber { get; set; }
}
[Table("SalesOrders")]
public class SalesOrder : SalesDocumentHeader
{
[Required]
public String CustomerOrderNumber { get; set; }
public DateTime? DeliverBy { get; set; }
public virtual SortableBindingList<SalesOrderLine> Lines { get; set; }
}
The context contains
public DbSet<SalesOrder> SalesOrders { get; set; }
public DbSet<SalesDocumentHeader> SalesDocumentHeaders { get; set; }
It doesn't strictly need the SalesOrders DBSet, since SalesOrder inherits from SalesDocumentHeader however I find it convenient.
It seems to work OK, but I am worried that there are 2 ways of reaching the same record , am I doing something wrong?
Usually you only need to keep the DBSet for the base table. This helps when you have multiple derived tables (call them A and B) and you need to decide the actual type dynamically.
For example if you have another entity which references type A or B (like a user can have different types of contact information), you can reference the base table and EF will resolve the correct concrete type at runtime. Though of course this adds some extra casting code.