Entity Framework code first for object with collection of properties - c#

I'm using C# and .NET Core with MySql and Entity Framework.
I have an object with a collection of properties. Like this:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<Property> Properties { get; set; }
}
public class Property
{
public int Id { get; set; }
public string Name { get; set; }
public object Value { get; set; }
}
In this case in the database, I should have tables Products, Properties (where property is described, like name and some additional info), and link table ProductProperties, storing product Id, property Id and Value.
But I can't figure out how to do this with a code-first approach.
How could I implement it with code first?
Is it a good way to create one more entity PropertyValue and store it under Product?

Something like this should give you a 1-to-many relationship, although you need to give Value a type, like string to store it in the database, often for dynamic solutions like this you would then maybe add a type to specify the type to deserialize into, but since you then deserialize anyway you could also just add things as json or something else in the db.
public class Product
{
public int Id {get; set;}
public string Name{get; set;}
public ICollection<Property> Properties{get; set;}
}
public class Property
{
public int Id {get; set;}
public string Name {get; set;}
public string Value {get; set;}
public int ProductId {get; set;}
}
Unless you are making a very dynamic system, it doesn't seem right to have the properties as a table, depends a lot of what you are making, and maybe key-value db might be a better tool for the job if thats what your main problem is, as with most complicated things, it depends.
This example is a convention based approach, which is why properties like ProductId have to be called exactly that. You can look at EntityTypeConfigurations if you want more control of names and relationships and such, or use data annotations to achieve the same job.

Ok so create a table like this:
public class ProductProprties
{
public int ProductId {get; set;}
public Product Product {get;set;}
public int PropertyId {get; set;}
public Property Property {get;set;}
//other props
}
If you are using EntityFramework Core, then you have to add this to your databse context as well:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ProdcutProprties>().HasKey(x => new { x.ProductId , x.PropertyId });
}

Related

Relationship with string field EF Core 7.0

how are you?
I have a need to relate 2 tables one to many with a string field that are not table keys
public class Schedule
{
public int Id { get; set}
public string Comment { get; set;}
public string Name { get; set;}
}
public class Products
{
public int Id { get; set;}
public string Product { get; set;}
}
I need to relate Schedule.Name with Products.Product
How can I do this in a simple way
I'm using EF Core 7.0
I read several posts, but usually the tutorials are referring to standard relationships. Where an ID field relates to another ID from another table
Thanks
I tried using data annotation and api fluent, but I couldn't get a result

How to populate nested object in model?

I'm creating a database first web api using entity framework. I created my models by creating ADO.NET Entity Models that were populated automatically with the fields on the tables that I selected. I want to be able to take some of those fields and group them in a custom object so when the xml is displayed, they are displayed as a child node.
An example is if I had the class with the following attributes
public class Person
{
public string firstname{get; set;}
public string lastname{get; set;}
public string street{get; set;}
public string city{get; set;}
public string zip{get; set;}
}
I want it to be something like this instead
public class Person
{
public string firstname{get; set;}
public string lastname{get; set;}
public string address{get; set;}//where address contains street, city, and zip
}
How would I go about in implementing this new Person class and populating the data of the custom object with my dbcontext
It is impossible to change three string properties to the one string property. How you can divide Address property to the street city and zip for example in case when street has two words?
You can create Address class (with three properties) and use it your Person class. But you will have problems when you try to regenerate/update your model - in such case is better to use code first approach.
Belongs-to Relationship
I think what you're looking for is a relationship between Person and a new class called Address.
To reference your new Address class inside Person, you would do the following:
public class Person
{
...
public Guid AddressId { get; set; }
public Address { get; set; }
}
Entity Framework will then associate an Address with the given AddressId with a Person.
Inside Address you can do something like this:
public class Address
{
public string City { get; set; }
public string Street { get; set; }
...
}
Eager Loading
To make sure an Address is loaded when a Person is loaded, you can use Entity Framework's Eager Loading capabilities, such as:
context.Person.Include(x => x.Address)
Use enumerable List like
public class Person
{
public string firstname{get; set;}
public string lastname{get; set;}
public List addresses{ get; set; }
}
public class Address
{
public string street{get; set;}
public string city{get; set;}
public string zip{get; set;}
}

create entity with reference to another existing object

public class Link
{
public virtual Category Category { get; set; }
}
public class Category
{
public Category(){Links = new List<Link>}
public virtual IList<Link> Links {get; set;}
}
My problem is when I wanna create Link with reference to Category I got a error with foreign key.
I try to use fluent api, get threw repo category but still the same problem.
EF want to create new object of Category.
To pass data I get to controller second repo(category) and pass to viewbag data.
4 hours spent to find solution but still I've got nothing, could someone explain it to me how it work that I cant pass that :/
Both of your classes need properties that can be mapped to primary keys. This is most commonly done with an int called ID...
public class Link
{
public int ID { get; set; }
public virtual Category Category { get; set; }
}
public class Category
{
public int ID { get; set; }
public Category(){Links = new List<Link>}
public virtual IList<Link> Links {get; set;}
}

Entity Framework Include without nested properties

I have two related entities called DataTag and TagSource that look like the following:
public class DataTag : BaseModel
{
[Column("DataTagId")]
public override Guid ID { get; set; }
public string Tag { get; set; }
public Guid TagSourceId { get; set; }
public TagSource TagSource { get; set; }
}
public class TagSource : BaseModel
{
[Column("TagSourceId")]
public override Guid ID { get; set; }
public string Description { get; set; }
public bool IsInternal { get; set; }
public string Source { get; set; }
public ICollection<DataTag> DataTags { get; set; }
}
I am allowing the user to Include the navigation properties through the url like "/api/DataTags?Include=TagSource". The problem is when I include the TagSource, it also includes the collection of DataTags in that object which I don't want unless the user specifies it (For example "/api/DataTags?Include=TagSource.DataTags". Is there any way to stop that property from being loaded when I include the TagSource? I have tried making the properties virtual and turning lazy loading off globally but that didn't work. The reason I haven't marked them virtual is because I am using AutoMapper and I only want to include the navigation properties that the user specifies.
As in the comments you need to create a DTO object. There is a good article here detailing how to do this with WebAPI
http://www.asp.net/web-api/overview/data/using-web-api-with-entity-framework/part-5
Edit.
The problem with this is you will need a lot of different DTO objects for each possible outcome which could become messy. If your return type is JSON you can add this attribute to your properties:
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
Firstly : Apologies for my English.
Secondly : I had the same issue with a code first database model that creates foreign keys this way : public virtual Collection<Object> Objects {get; set;}
and I found a workaround by setting the property setter as private:
public virtual Collection<Object> Objects {get; private set;}
Then the EF cannot populate the Objects collection because with a private set you can only assign a value in constructors.

EF ObservableListSource Specify ForeignKey

I have two entities: Employee & Contract.
In the Contract entity I have the properties AddedByEmployee & AssignedToEmployee.
I want a collection navigation property in my Employee class but how do I reference the correct key in the Contract class?
So far I have:
public class Employee
{
public int EmployeeID {get; set;}
public string Name {get; set;}
private readonly ObservableListSource<Contract> _Contracts = new ObservableListSource<Contract>();
public virtual ObservableListSource<Contract> Contracts { get { return _Contracts; }
}
public class Contract
{
public int ContractID {get; set;}
public string Name {get; set;}
public int AddedByEmployeeID {get; set;}
public int AssignedToEmployeeID {get; set;}
[ForeignKey("AddedByEmployeeID")]
public virtual Employee AddedByEmployee { get; set; }
[ForeignKey("AssignedToEmployeeID")]
public virtual Employee AssignedToEmployee { get; set; }
}
So basically: How do I let the ObservableListSource<Contract> know it is the AddedByEmployeeID I want to map to?
Thanks
You can do this by either using DataAnnotations or the Fluent API.
Doing it with DataAnnotations you can add the InverseProperty attribute to either your Contracts or AddedByEmployee property (or both, but that is not necessary).
This will tell Entity Framework that a relationship should be made between Contracts and AddedByEmployee.
[InverseProperty("AddedByEmployee")]
public virtual List<Contract> Contracts
{
get { return _Contracts; }
}
If you want to use the Fluent API instead, you simply have to explicitly define the relationship like this:
modelBuilder.Entity<Employee>()
.HasMany(p => p.Contracts)
.WithRequired(p => p.AddedByEmployee)

Categories

Resources