I have two models
class Employee {
[Key]
public int ID {get;set;}
public string FirstName {get;set;}
public string LastName {get;set;}
public int EmploymentID {get;set;}
[Required, ForeignKey("Employment")]
public virtual Employment Employment {get;set;}
}
class Employment {
[Key, ForeignKey("Employee")]
public int ID {get;set;}
public string Department {get;set;}
public int OfficePhone {get;set;}
public int EmployeeID {get;set;}
public virtual Employee Employee {get;set;}
}
basically each employee has employment information in the Employment class. I'm not sure if I need the [Required] annotation there, and I don't know if I'm putting the [ForeignKey] annotation in the right spot either.
The problem is, when I try to create a new scaffolded item, it gives me this error:
Unable to determine the principal end of an association between the types 'Bla.Models.Employee' and 'Bla.Models.Employment'. The principal end of this association must be explicitly configured using either the relationship fluent API or data annotations.
Thank you for the help
EDIT
assume the Employee model has the following instead:
class Employee {
[Key]
public int ID {get;set;}
public string FirstName {get;set;}
//note the return value is an ICollection object
public ICollection<LastName> LastName {get;set;}
public int EmploymentID {get;set}
public virtual Employment Employment {get;set;}
}
and the Employment model remains the same,
and the LastName field has the following class
class LastName {
public string EmployeeLastName {get;set;}
//assuming last name can change, and employee had a different last name at some point
public int year{get;set;}
}
is it incorrect to make the LastName class, a model? or should it remain a model?
how can I make it so that its just a resource class (i.e. not a model to be made into a table)
further, will this kind of thing break the relationships between employee/employment models?
because I'm still getting the error and not sure why; by the way, I have many of these classes like the "LastName" example and they are all currently under models, and I'm not sure if they should be a model or some resource class, and if so, I don't know where they are supposed to go
also heres my dbcontext
public class MyDbContext : DbContext
{
public MyDbContext()
: base("MyDbContext")
{
}
public DbSet<Employee> Employees { get; set; }
public DbSet<Employment> Employments { get; set; }
public DbSet<BasicAddress> Adresses { get; set; }
public DbSet<Department> Departments { get; set; }
public DbSet<BasicDate> BasicDate { get; set; }
public DbSet<BasicPhoneNumber> BasicPhoneNumber { get; set; }
public DbSet<EmployeeIdentification> EmployeeIdentification { get; set; }
public DbSet<FederalIdentification> FederalIdentification { get; set; }
public DbSet<JobTitle> JobTitle { get; set; }
public DbSet<LastName> LastName { get; set; }
public DbSet<MaritalStatus> MaritalStatus { get; set; }
public DbSet<OfficeLocation> OfficeLocation { get; set; }
}
everything other than employee and employment is a basic class (like the LastName class), I'm not sure if they should be with "models" and made into tables or just be regular classes on the side. If they shouldn't be made into tables, where should they go in the project?
thank you again for the help! (please let me know if anything needs clarification)
Employment cannot exist with Employee. As per the law of foreign relationship the Employment must not be saved without Employee. Thus with the help of [ForeignKey] notation you need to advise Employment that Employee relation should be maintained.
Employment is dependent on Employee. Thus you got to tell Employment that you are got to have a linking with the principal.
Thus dependent class must have Employee id reference.
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
namespace TestConsole
{
public class Employee
{
public int ID { get; set; }
[Required]
public string FirstName { get; set; }
public string LastName { get; set; }
[Required]
public virtual Employment EmploymentDetails { get; set; }
}
public class Employment
{
[Key, ForeignKey("Employee")]
public int ID { get; set; }
public string Department { get; set; }
public int OfficePhone { get; set; }
public virtual Employee Employee { get; set; }
}
internal class Program
{
public TestConsoleDbContext MyDbContext { get; set; }
public Program()
{
MyDbContext = new TestConsoleDbContext();
}
private static void Main(string[] args)
{
var program = new Program();
var records = from p in program.MyDbContext.Employees
select new { p.EmploymentId, p.LastName, p.Employment.Department };
foreach (var r in records)
{
Console.WriteLine("EmploymentID: {0} {1} Department: {2}", r.EmploymentId, r.Department);
}
Console.ReadLine();
}
}
}
using System.Data.Entity;
namespace TestConsole
{
internal class TestDbContext : DbContext
{
public IDbSet<Employee> Employees { get; set; }
public IDbSet<Employment> Employments { get; set; }
}
}
I don't think Employment field needs the Required attribute and the ForeignKey attribute must be applied to the EmploymentID field.
Related
I have following RecipeModel, IngredientModel and RecipePartModel classes which represent the DTO classes for the frontend user:
public class RecipeModel
{
public Guid Id { get; set; }
public string Name { get; set; }
public string ImageUrl { get; set; }
public string Description { get; set; }
public IEnumerable<RecipePartModel> RecipeParts { get; set; }
}
public class IngredientModel
{
public Guid Id { get; set; }
public string Name { get; set; }
}
public class RecipePartModel
{
public Guid Id { get; set; }
public IngredientModel Ingredient { get; set; }
public string Unit { get; set; }
public decimal Quantity { get; set; }
}
Here are my entity classes:
public class Recipe : BaseEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
public string ImageUrl { get; set; }
public string Description { get; set; }
public virtual IEnumerable<RecipePart> RecipeParts { get; set; }
}
public class Ingredient : BaseEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid Id { get; set; }
public string Name { get; set; }
public int Amount { get; set; }
public virtual IEnumerable<RecipePart> RecipeParts { get; set; }
}
public class RecipePart : BaseEntity
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public Guid Id { get; set; }
public Ingredient Ingredient { get; set; }
public Recipe Recipe { get; set; }
public string Unit { get; set; }
public decimal Quantity { get; set; }
}
My question is - how can I map the Recipe to RecipeModel using AutoMapper? I tried something like this but I assume it is bad, because it just join all the RecipeParts for the whole database, am I correct?
public class DomainProfile : Profile
{
public DomainProfile()
{
CreateMap<Ingredient, IngredientModel>().ReverseMap();
CreateMap<Recipe, RecipeModel>()
.ForMember(x => x.RecipeParts, opt => opt.MapFrom(src => src.RecipeParts));
}
}
To answer your question about how to use AutoMapper to map a type to another type, there are many ways of doing this. Documentation is here: http://docs.automapper.org/en/stable/Getting-started.html.
I wrote a console app and got it working in the quickest way I know possible using your code. When I debug this, and check inside recipeModel, it references a list of RecipePartModels with a single RecipePartModel. Inside that RecipePartModel, it references an IngredientModel.
static void Main(string[] args)
{
var profile = new DomainProfile();
Mapper.Initialize(cfg => cfg.AddProfile(profile));
var recipe = new Recipe
{
RecipeParts = new List<RecipePart>
{
new RecipePart()
{
Ingredient = new Ingredient()
}
}
};
var recipeModel = Mapper.Map<Recipe, RecipeModel>(recipe);
Console.ReadKey();
}
To answer your concern about getting all recipes from the database, if you're using Entity Framework, it depends on if you have lazy loading turned on. Lazy loading ensures that, when you get a recipe from the database, the recipe parts will not be loaded. They will only be loaded when you access the recipe part directly later on in the program flow. Lazy loading is turned on by default so this is the default behaviour. If you turn it off, you've enabled eager loading which loads all recipe parts and in turn their ingredient.
This might help: http://www.entityframeworktutorial.net/lazyloading-in-entity-framework.aspx.
There is nothing bad about this mapping. In fact you don't even need the ForMember call as this is the default convention. The mapping will simply convert each element in the entity child collection to a corresponding model object.
Of course, whether you load your entities in an efficient manner is another matter. If you load a large amount of Recipe entities, and lazy load the RecipeParts collections for each, you will have a major "SELECT N+1" problem. But this is not the fault of AutoMapper.
I've been building application using TPT (Table-Per-Type) in entity framework 6.
I have these classes
public class Person
{
public Guid Id { get; set; }
public string Name { get; set; }
}
public class Customer : Person
{
public string BillingAddress { get; set; }
}
public class Vendor : Person
{
public string Address { get; set; }
}
public class IndividualCustomer : Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Birthday { get; set; }
}
public class CorporateCustomer : Customer
{
public string ContactPerson { get; set; }
public string CorporateTaxNo { get; set; }
}
public class SalesInvoice
{
public Guid Id { get; set; }
public Guid CustomerId { get; set; }
public Customer Customer { get; set; }
}
The query is very ugly and took a long time to generate when i query against the base class (which are Person and Customer), But quite ok when querying the derived class (IndividualCustomer & CorporateCustomer).
I have read that using TPT is very bad for performance and i'm considering to use TPH (Table-Per-Hierarchy) because of this. But when i use TPH, when adding SalesInvoice, i will have to validate if the user is sending the correct CustomerId. Because database will allow the user sending a vendorid as CustomerId. While using TPT, database will throw error. So TPH will add complexity when doing CRUD.
Are there any suggestion how to improve TPT query on my case?
Note:
I found that when querying the base class, if i specify which fields i want to retrieve, eg Select(x => new {x.Id, x.Name}), the query looks better and does not include left outer join the derived classes.
My Queries:
//Querying base class
var people = ctx.People.Select(x => new {x.Id, x.Name}).ToList();
//Querying derived class
var corporates = ctx.CorporateCustomers.ToList();
I've been lurking around for quite some time, so here's the first question ;)
I've been playing with Entity Framework 5.0 Code First and I want to do following:
I have two entities and I want every entity to have relation to Address entity in the following way:
I have one Address entity which stores address values, it doesn't have relation to entities for which it has values, instead
There's another entity AddressBook which has reference to Address entity and the coresponding entities (Person, Company, some others in the future)
Here's code:
public partial class Address : BaseEntity
{
[Key]
public int ID { get; set; }
public string Street { get; set; }
public string CityName { get; set; }
public int? PostalCode { get; set; }
public virtual ICollection<Person> Persons { get; set; }
public virtual ICollection<Company> Companies{ get; set; }
}
public partial class Person : BaseEntity
{
[Key]
public int ID { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
}
public partial class Company: BaseEntity
{
[Key]
public int ID { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
}
What will this do is create database schema with tables:
Address
AddressPerson (with composite primary key)
Address_ID
Person_ID
AddressCompany
Address_ID
Company_ID
People
Companies
Here's what I want to do:
Address
AddressBook
Address_ID (PK)
Person_ID (FK)
Company_ID (FK)
People
Companies
What I want to do is have table like AddressBook:
public partial class AddressBook
{
[Key]
public int ID { get; set; }
public virtual Address Address { get; set; }
public virtual Person Person { get; set; }
public virtual Company Company { get; set; }
}
I'm not sure how to define navigational properties in Person and Company class.
They should have ICollection<Address> Addresses navigational property, because I want them to work just with collection of addresses without knowing about underlying AddressBook.
Is it possible to do this with DbModelBuilder or should I write code inside getter and setter of ICollection<Address> Addresses property and get addresses from AddressBook?
Thanks!
You cannot create a mapping in a way that Entity Framework would understand the Addresses collections in Person and Company as true navigation properties (which support eager and lazy loading and so on). For this you need indeed AddressBooks collections. You can add the Addresses as not mapped and readonly helper properties then:
public partial class Person : BaseEntity
{
[Key]
public int ID { get; set; }
public virtual ICollection<AddressBook> AddressBookEntries { get; set; }
public IEnumerable<Address> Addresses
{
get { return AddressBookEntries.Select(ab => ab.Address); }
}
}
(The same with Company.)
An alternative and in my opinion better approach would be to create a common base class for Person and Company, move the Addresses collection into that base class and have a single many-to-many relationship and single join table between this base class and Address:
public abstract class EntityWithAddresses : BaseEntity
{
[Key]
public int ID { get; set; }
public virtual ICollection<Address> Addresses { get; set; }
}
public partial class Person : EntityWithAddresses
{
}
public partial class Company : EntityWithAddresses
{
}
Address has a navigation collection to the new base class:
public partial class Address : BaseEntity
{
[Key]
public int ID { get; set; }
public string Street { get; set; }
public string CityName { get; set; }
public int? PostalCode { get; set; }
public virtual ICollection<EntityWithAddresses> EntityWithAddresses { get; set; }
}
So i am working with entity code firest and i have a user class that looks like this:
public class User
{
[Key]
public string Username { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime LastModified { get; set; }
}
I am trying to make a "friends table" and no matter what i come up with I get an error on the db creation. This is what I Currently have in the Friends Class:
public class Friend
{
[Key, ForeignKey("User")]
public virtual User MyUser { get; set; }
[Key,ForeignKey("User")]
public virtual User MyFriend { get; set; }
public bool IsAccepted { get; set; }
}
this is the error i get:
The ForeignKeyAttribute on property 'MyUser' on type 'Core.Model.Friend' is not valid. The foreign key name 'User' was not found on the dependent type 'Core.Model.Friend'. The Name value should be a comma separated list of foreign key property names.
What am I missing?
You need to use the Column attribute. Normally I would use something like this:
public class Friend
{
[Key]
[Column(Order = 0)]
public int MyUserId { get; set; }
[Key]
[Column(Order = 1)]
public int MyFriendId { get; set; }
[ForeignKey("MyUserId")]
public virtual User MyUser { get; set; }
[ForeignKey("FriendId")]
public virtual User MyFriend { get; set; }
public bool IsAccepted { get; set; }
}
I'm not sure what would happen if you map the Column attribute directly to the navigation property. You can try it if you like and see what happens.. but the above generally works for me.
Alternatively, if you change to use fluent mapping, you can do something like this:
HasKey(u => new { u.MyUserId , u.MyFriendId });
I'm working with sqlite and the c# sqlite-net library.
Some of my entities:
public class Product
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
[MaxLength(50)]
public string Name { get; set; }
[MaxLength(50)]
public string Brand { get; set; }
[MaxLength(50)]
public string Type { get; set; }
[MaxLength(50)]
}
public class ProductImage
{
public int Id { get; set; }
public string Name { get; set; }
public string Container { get; set; }
public int ProductId { get; set; }
}
Now all entities belong to a user and the user should always work only with his own entities. So when I insert an entity in the database I want to store the userId with it.
However... I don't want to add the userId to all my domain classes.
I'm storing my entities like this right now:
await _databaseManager.GetDatabaseInstance().InsertAsync(entity);
and selecting like this:
var products = await _databaseManager.GetDatabaseInstance().Table().ToListAsync();
So is there a way with sqlite-net to add the userId to the database without adding it to all domain classes?
Doesn't it support inheritance, as in looking at the type's hierarchy? I would suggest it would, or at least should. So, if it does you could use an abstract base class or an interface. Something like this:
public abstract class StandardEntity {
public int UserId { get; set; } // decorate with attributes as necessary
}
And inherit:
public class Product : StandardEntity {
}