How do I map a small object graph using Entity Framework Code First 4.1? - entity-framework

I have a very small object graph that I'm using:
public struct Address
{
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
etc...
}
public class User
{
public Address HomeAddress { get; set; }
public Address WorkAddress { get; set; }
public string FirstName { get; set; }
etc...
}
Using Entity Framework 4.1, how would I map this structure to one table so that they're mapped to columns like:
HomeAddressLine1
HomeAddressLine2
WorkAddressLine1
WorkAddressLine2
FirstName
LastName
etc...

EF doesn't support structures. You must use class for your Address and map it as complex type:
public class Address
{
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
}
public class User
{
public int Id { get; set; }
public Address HomeAddress { get; set; }
public Address WorkAddress { get; set; }
public string FirstName { get; set; }
}
public class Context : DbContext
{
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<User>()
.Property(u => u.HomeAddress.AddressLine1)
.ColumnName("HomeAddressLine1");
// Use the same pattern for all columns of HomeAddress and WorkAddress
}
}

Related

EF 6 Code First Mapping one-to-many

Can someone please help me with mapping the following hierarchy with EF 6 code first? I can find anything useful for the below example in the documentation.
namespace Contacts {
public class Person
{
public Person()
{
this.Emails = new HashSet<Email>();
}
public long Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public virtual ICollection<Email> Emails { get; set; }
}
public class Company
{
public Company()
{
this.Emails = new HashSet<Email>();
}
public long Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Email> Emails { get; set; }
}
public class Email
{
public string Value { get; set; }
public string Label { get; set; }
public string TargetId { get; set; }
public string TargetType { get; set; }
}
}
TargetType can be set to Company or Person depending on the entity that contains the Email instance.
DB Schema:

EF Data Annotation - Foreign Key - How to Customize

My issue is the following. I have a Model for an Address table as follows.
public partial class ADDRESS
{
public ADDRESS()
{
this.ADDRESS_ID = Guid.NewGuid();
}
public Guid ADDRESS_ID { get; set; }
public string ADDRESS_LINE { get; set; }
public string CITY { get; set; }
public Guid? STATE_ID { get; set; }
public string ZIP { get; set; }
}
This ADDRESS model is used throughout my application and has different validation requirements depending on where it is placed within a form.
I am wondering if there is a way to customize the data annotations. For example, the ADDRESS_LINE and CITY properties are required for OCCUPATION_ADDRESS but not required for WORK_LOCATION_ADDRESS.
public class OCCUPATION_DETAILS
{
public string COMPANY_NAME { get; set; }
public string JOB_TITLE { get; set; }
etc...
public Guid OCCUPATION_ADDRESS_ID { get; set; }
public virtual ADDRESS OCCUPATION_ADDRESS { get; set; }
public WORK_LOCATION_ID { get; set; }
public virtual ADDRESS WORK_LOCATION_ADDRESS { get; set; }
}
Or it could be that basic validation is the same (zip has to be 5 digits), but I need to adjust the "DisplayName" that is used to match the label of the form it is within.
Trying to minimize the amount of copied models I have set up; otherwise maintenance will be a nightmare.
you can achieve this by using the idea of inheritance
how?
public abstract class ADDRESS
{
public ADDRESS()
{
this.ADDRESS_ID = Guid.NewGuid();
}
public Guid ADDRESS_ID { get; set; }
public string ADDRESS_LINE { get; set; }
public string CITY { get; set; }
public Guid? STATE_ID { get; set; }
public string ZIP { get; set; }
}
public parital class OCCUPATION_ADDRESS: ADDRESS,IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(string.IsNullOrWhiteSpace(ADDRESS_LINE))
yield return new ValidationResult("Address line is required!",new string[]{"ADDRESS_LINE"});
}
}
public parital class WORK_LOCATION_ADDRESS: ADDRESS,IValidatableObject
{
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
}
}
// and your Occupation details class will be like: instead of ADDRESS you will use the corresponding derived classes
public class OCCUPATION_DETAILS
{
public string COMPANY_NAME { get; set; }
public string JOB_TITLE { get; set; }
etc...
public Guid OCCUPATION_ADDRESS_ID { get; set; }
public virtual OCCUPATION_ADDRESS OCCUPATION_ADDRESS { get; set; }
public WORK_LOCATION_ID { get; set; }
public virtual WORK_LOCATION_ADDRESS WORK_LOCATION_ADDRESS { get; set; }
}
and the inheritance should be Table per Hierarchy (TPH)
for more information about TPH check this Table per hierarchy
hope that this will help you
regards

Entity Framework : get related entities

I created a WCF service with Entity Framework.
I have 2 tables : Theaters and Locality. Locality as a foreign key in Theaters.
My method :
public theater[] GetTheaters()
{
using (Entities context = new Entities())
{
return context.theater.ToArray();
}
}
I have to remove the "virtual" keyword from "public virtual locality locality { get; set; }" in my theater class. Otherwise, I get a CommunicationException.
But when I do that, I get my list of theaters but the locality is null...
How can I get the locality ?
Thanks
My model class ( I also have other entities) :
public partial class locality
{
public locality()
{
this.theater = new HashSet<theater>();
}
public int idLocality { get; set; }
public int npa { get; set; }
public string locality1 { get; set; }
public ICollection<theater> theater { get; set; }
}
public partial class theater
{
public theater()
{
this.session = new HashSet<session>();
}
public int idTheater { get; set; }
public string name { get; set; }
public string address { get; set; }
public int idLocality { get; set; }
public double latitude { get; set; }
public double longitude { get; set; }
public int seats { get; set; }
public string phone { get; set; }
public string email { get; set; }
public bool threeD { get; set; }
public locality locality { get; set; }
public ICollection<session> session { get; set; }
}
Here is the error that I get :
"Object graph for type 'locality' contains cycles and cannot be serialized if reference tracking is disabled.
EDIT :
The solution that I found :
In my locality class, I had a Collection of theaters.
I had to add "private to the setter like this :
" public ICollection theater { get; private set; }"
So it works, but I still have a problem, I can't access to the theaters from the locality entity anymore. (no more bi-directional)
If you want to force related entities to load, you can use the Include method to do so. By default, related entities are loaded Lazily.
Your example would be:
public theater[] GetTheaters()
{
using (Entities context = new Entities())
{
return context.theater.Include(t=>t.Locality).ToArray();
}
}
You can use eager loading or explicit loading. With eager loading you use the Include extension method:
return context.Theater.Include(t => t.Locality).ToArray();
You're missing the correct annotations to create the relationships. See the code below. (or create the relationships yourself if using the FluentAPI)
Look for the [Key] and [ForeignKey] annotations, as well as the virtual keyword.
public partial class locality
{
public locality()
{
//this.theater = new HashSet<theater>();
}
[Key]
public int idLocality { get; set; }
public int npa { get; set; }
public string locality1 { get; set; }
public virtual ICollection<theater> theaters { get; set; }
}
public partial class theater
{
public theater()
{
//this.session = new HashSet<session>();
}
[Key]
public int idTheater { get; set; }
public string name { get; set; }
public string address { get; set; }
public int idLocality { get; set; }
public double latitude { get; set; }
public double longitude { get; set; }
public int seats { get; set; }
public string phone { get; set; }
public string email { get; set; }
public bool threeD { get; set; }
[ForeignKey("idLocality")]
public virtual locality locality { get; set; }
//public ICollection<session> session { get; set; }
}

Automapper DTO to Entity Nested Mapping

I have entities:
public class Person
{
//properties
public virtual State State { get; set; }
}
public class State
{
//properties
public int StateId { get; set; }
public string StateName { get; set; }
public virtual Address Address{ get; set; }
}
public class Address
{
//properties
public int AddressId { get; set; }
public string City{ get; set; }
public int PostalCode { get; set; }
}
And i have a flatten DTO called PersonDetails
public class PersonDetails
{
//properties
public string City { get; set; }
public string StateName { get; set; }
public int PostalCode { get; set; }
}
When I do the mapping it works but it creates a new State and Adress for the Person entity.
How would I use AutoMapper to map from PersonDetails to PersonEntity?

Entity Framework 4.3 CF many - to - many relationship saving object?

When creating many to many relationship using EF 4.3 code first approach, I cannot save data to connecting table, also cannot any examples on how to fill this table using saving object to Icollection... Here is my example:
MODELS
public class Hospital
{
//PK
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string County { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public Guid User_Id { get; set; }
//FK
public virtual ICollection<Operator> Operators { get; set; }
}
public class Operator
{
//PK
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Dob { get; set; }
public string Email { get; set; }
//FK
public virtual ICollection<Hospital> Hospitals { get; set; }
}
public class Project: DbContext
{
public DbSet<Hospital> Hospitals { get; set; }
public DbSet<Operator> Operators { get; set; }
}
CONTROLLER
public void AddOperater()
{
Hospital h = new Hospital();
h = db.Hospitals.Single(a=>a.Id ==1);
var o = new Operator();
o.FirstName = "John";
o.LastName = "Doe";
o.Dob = new DateTime(1988,2,12);
o.Email = "johndoe#gmail.com";
o.Hospitals.Add(h);
db.SaveChanges();
}
With this approach I keep getting error here: o.Hospitals.Add(h); even when my Hospital instance is filled with data. How exactly to save data to both tables, the dbo.Operators and dbo.OperatorHospital which is relationship table?
o.Hospitals.Add(h) will fail because the list is a null list. You cannot call Add() on a null list. Typically most people get around this by instantiating the list in the constructor of the entity... like so... the current line is blowing up due to a CSharp issue.
public class Hospital
{
//PK
[Key]
public int Id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
public string City { get; set; }
public string County { get; set; }
public string UserName { get; set; }
public string Password { get; set; }
public Guid User_Id { get; set; }
//FK
public virtual ICollection<Operator> Operators { get; set; }
public Hospital()
{
Operators = new List<Operator>();
}
}
public class Operator
{
//PK
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Dob { get; set; }
public string Email { get; set; }
//FK
public virtual ICollection<Hospital> Hospitals { get; set; }
public Operator()
{
Hospitals = new List<Hospital>();
}
}