EF - One to one relationship - entity-framework-5

I have the following class:
public class FinanceiroLancamento
{
/// <summary>Identificação</summary>
public override int Id { get; set; }
/// <summary>Financeiro caixa</summary>
public FinanceiroLancamentoCaixa FinanceiroLancamentoCaixa { get; set; }
}
public class FinanceiroLancamentoCaixa
{
/// <summary>Identificação</summary>
public override int Id { get; set; }
/// <summary>Identificação do lançamento financeiro</summary>
public int IdFinanceiroLancamento { get; set; }
}
When I try to map and execute migration it´s return:
Property name 'IdFinanceiroLancamento' was already defined.
To solve this problem I needed to comment idfinanceirolancamento and map like this:
HasRequired(e => e.FinanceiroLancamentoCaixa)
.WithRequiredPrincipal()
.Map(m => m.MapKey("IdFinanceiroLancamento"));
The question is:
How can I this FK (FinanceiroLancamento -> FinanceiroLancamentoCaixa) keeping the "IdFinanceiroLancamento { get; set; }"?
This is very important in my case to use later in the class.
Ps: FinanceiroLancamento does not need a FinanceiroLancamentoCaixa, but when FinanceiroLancamentoCaixa exists he needs a FinanceiroLancamento.
Best regards.
Wilton Ruffato Wonrath

Entity Framework requires that 1:1 mappings share the same primary key. In your case, you are trying to use a different member as the mapping id. Also, do not override the base class id, just inherit it.
What you want Is this:
.HasRequired(e => e.FinanceiroLancamentoCaixa)
.WithRequiredPrincipal();
Entity Framework does not allow you to use a 1:1 that is not a shared primary key, so you can't do it in EF. If you absolutely need this, you may have to do it as a stored procedure and call it from EF.
The reason you can't have a 1:1 like this is because the data model allows you to set IdFinanceiroLancamento to the same ID in more than one record, thus breaking your 1:1.
Basically, EF will not allow you to create models with mappings that allow for a violation of the mapping, even if you never create duplicates, it's still a possibility. EF doesn't know about unique constraints either so placing a unique constraint won't tell EF that it's ok.
If you'd like to see this feature, I suggest you vote for it at the EF uservoice:
http://data.uservoice.com/forums/72025-entity-framework-feature-suggestions/suggestions/1050579-unique-constraint-i-e-candidate-key-support

Related

Projecting from a model with an integer property to class with Enum property

I have my model classes set up with the integer properties just as they are stored in the database. So a sample model might look like:
public class TaskModel
{
public int TaskId { get; set; }
public int TaskStatus { get; set; }
}
But on my actual business classes I want to use enums, so the matching business class would look like:
public class Task
{
public int TaskId { get; set; }
public Status TaskStatus { get; set; }
}
I then want to use Automapper's LINQ projection features to query these business classes, like:
return db.Tasks.Where( t => t.TaskStatus == 1 ).Project().To<Task>();
But when I do this I get this error:
Unable to create a map expression from System.Int32 to MyNamespace.TaskStatus
I've been able to resolve it by setting up the mapping as such:
Mapper.CreateMap<TaskModel, Task>()
.ForMember(t => t.TaskStatus, opt => opt.MapFrom(m => (TaskStatus)m.TaskStatus))
.ReverseMap();
This seems to work (so far), but my question is there a better or DRYer way to do this. The problem is I will need to do this for a ton of properties across a ton of models and classes. Seems like there should be a simpler way to do what is essentially a simple cast with having to write 100's of lines of mapping code.
You can do this with a type converter:
Mapper.CreateMap<int, TaskStatus>()
.ProjectUsing(src => (TaskStatus)src);
This will be used everywhere. The reason you have to do this is because some LINQ providers have different ways of dealing with enum conversions and persistence, so you have to use the right expression it expects (and AutoMapper doesn't assume it knows what EF or NHibernate or whatever need).

How to exclude property in EF using PCL?

I've got a POCO defined, something like this:
public class Customer
{
public string Name { get; set; }
public DateTime DOB { get; set; }
[System.ComponentModel.DataAnnotations.Schema.NotMapped] // <- this is what I want to do, but can't in PCL
public AccountCollection Accounts { get; set; }
}
The above has the "NotMapped" attribute, which is what I want - but it's not available in a portable class library (PCL). The thing is, the class I need is defined in an assembly that WILL be used on the portable device but it will be filled from entity framework on the web, which DOES have access to the NotMapped attribute. If I could find a way to add the property to EF's "NotMapped" list, that would be ideal.
Is there a way to get this to work? That is, a way to do what "NotMapped" does programmatically?
I've considered other workarounds, but none of them are ideal:
Could create a DAL separate from my domain layer and translate
between the two (but requires mapping and two models instead of one)
Could write custom EF queries and updates to ignore the property (but means writing all the linq/SQL/procs myself)
Found the answer in the Context's OnModelCreating() overload. Accessing the modelBuilder parameter it's possible to find the entity and ignore specific properties. This works even when the POCO is defined in a PCL.
For example:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
// Ignore Customer.Accounts
modelBuilder.Entity<Customer>().Ignore(c => c.Accounts);
}

Orchard: how to persist a record without content

Allright, this should be fairly easy.
I would like to persist some records for my module in Orchard (1.7.2) without those records being also a ContentPartRecord.
In other words, I would like to be able to persist in DB the following objects:
public class LogItemRecord
{
public virtual string Message { get; set; }
}
..which is already mapped on to the db. But notice that this class is not derived from ContentPartRecord, as it is most certainly not one.
However, when I call IRepository instance's .Create method, all I get is a lousy nHibernate exception:
No persister for: MyModule.Models.LogItemRecord
...which disappears if I do declare the LogItem record as having been inherited from ContentPartRecord, but trying to persist that, apart from being hacky-tacky, runs into an exception of its own, where nHibernate again justly complains that the Id value for the record is zero, though in not so many words.
So... how do I play nicely with Orchard and use its API to persist objects of my own that are not ContentParts / ContentItems?
I'm running 1.7.3 (also tested in 1.7.2) and have successfully been able to persist the following class to the DB:
public class ContactRecord
{
public virtual int Id { get; set; }
public virtual string Name { get; set; }
public virtual string JobTitle { get; set; }
public virtual string Email { get; set; }
public virtual string Phone { get; set; }
}
Here are the relevant lines from Migrations.cs
SchemaBuilder.CreateTable(
typeof(ContactRecord).Name,
table => table
.Column<int>("Id", col => col.Identity().PrimaryKey())
.Column<string>("Name")
.Column<string>("JobTitle")
.Column<string>("Email")
.Column<string>("Phone")
);
I'm going to assume that the code you've shown for LogItemRecord is the complete class definition when making the following statement...
I think that any Record class you store in the DB needs an Id property, and that property should be marked as Identity and PrimaryKey in the table definition (as I've done above).
When you create a *Record class which inherits from ContentPartRecord and setup the table like
SchemaBuilder.CreateTable(
"YourRecord",
table => table
.ContentPartRecord()
// more column definitions
);
then you get the Id property/PK "for free" by inheritance and calling .ContentPartRecord() in the Migration.
See the PersonRecord in the Orchard Training Demo Module for another example of storing a standard class as a record in the DB.

Request DTO map to Domain Model

I have the following Domain Model:
public class DaybookEnquiry : Entity
{
public DateTime EnquiryDate { get; set; }
[ForeignKey("EnquiryType")]
public int DaybookEnquiryTypeId { get; set; }
public string AccountNumber { get; set; }
[ForeignKey("User")]
public int UserId { get; set; }
#region Navigation Properties
public virtual User User { get; set; }
public virtual DaybookEnquiryType EnquiryType { get; set; }
public virtual ICollection<DaybookQuoteLine> QuoteLines { get; set; }
#endregion
}
This is inside of a project named DomainModel. Entity is just a base class which my domain models inherit from, it contains an Id field.
I then have other projects inside my solution called ServiceInterface and ServiceModel. ServiceInterface contains all my services for my application and ServiceModel contains my DTO's and routes etc.. I'm trying to follow the guidelines set out here: Physical Project Structure
My EnquiriesService contains a method to create a new enquiry in my database using a repository:
public void Post(CreateEnquiry request)
{
// Not sure what to do here..
// _repository.Insert(request);
}
My CreateEnquiry request looks like so:
[Api("POST a single Enquiry for Daybook.")]
[Route("/enquiries", "POST")]
public class CreateEnquiry : IReturnVoid { }
As you can see, the CreateEnquiry request object is empty. Do I need to add properties to it to match my Domain Model and then use AutoMapper or something similar to map the fields to my Domain Model and pass that into my repository?
The Insert method on my repository looks like so:
public virtual void Insert(T entity)
{
DbEntityEntry dbEntityEntry = DbContext.Entry(entity);
if (dbEntityEntry.State != EntityState.Detached)
{
dbEntityEntry.State = EntityState.Added;
}
else
{
DbSet.Add(entity);
}
DbContext.SaveChanges();
}
Yes. Your Service request, in this case CreateEnquiry needs to have all the properties you need in order to do whatever it is you want to do!
I've seen two different models for Create vs Update:
Use one request objects called, say, SetEnquiry that has a nullable id field. When null and using the POST HTTP verb, it internally creates a new object. And when not null and using the PATCH HTTP verb, it internally updates an object. You can use ServiceStack's implementation of AbstractValidator<T> to add logic such as if POST then id field needs to be null; and if PATCH then id field cannot be null. This will help ensure your data is always as it needs to be.
Create two request objects -- one for Create and one for Update. The Create doesn't even have an id field, and the Update has one and requires it. You can use the same validation technique used above, except applied to each class independently, so you don't need the conditional check of if this verb do this; if that verb do that.
How you map to your data model is up to you. You can use something like AutoMapper or you can use ServiceStack's built-in TranslateTo and PopulateWith methods. I personally take a middle ground: I created my own object extension methods called MapTo and MapFrom that interally call TranslateTo and PopulateWith respectively. Why did I do this? Because then I control those extensions inside my own namespaces and when I need to do special mappings (like a column name doesn't match up, or one object is more complex than the other, or I simply want to ignore a particular column from one of the objects) I simply overload the MapTo and MapFrom with explicit types, giving it higher specificity than the generic methods.
So back to your question specifically. Assuming you're using the built in TranslateTo your service method might look like this:
public void Post(CreateEnquiry request)
{
_repository.Insert(request.TranslateTo<Enquiry>());
}
One more thing: I generally return the object itself when doing a Create and Update. As fields can change (auto-calculated fields, for example) I like to return the object back to the caller. This is preference and has no real bearing on the answer I'm giving you. Just throwing it out there!

Mapping two properties one to many to the same collection

I'm using Entity Framework 4.3 code first. How do I create two "one to many"-relationships between two properties in class A and a collection in class B?
My model:
public class Shaft
{
public int Id { get; set; }
public virtual Coupling FirstEnd { get; set; }
public virtual Coupling SecondEnd { get; set; }
}
public class Coupling
{
public int Id { get; set; }
public virtual ICollection<Shaft> Shafts { get; set; }
}
Well, a one-to-many relationship is called one-to-many because there is one element on the first end of the relationship and many elements on the other end. You also can have a zero or one-to-many relationship which only means that the element on the not-many side can be null (or NULL in the database).
What you are trying to define is a two-to-many (or perhaps zero or one or two-to-many) relationship. Such a thing does not exist in a relational database nor does it exist in Entity Framework.
When you define a relationship with EF you always need pairs of two navigation properties in source and target class. It is possible to omit one of the navigation properties but that does not mean that you can move the end of this relationship to another navigation property that already belongs to another relationship.
In your specific case you have two relationships because your two navigation properties FirstEnd and SecondEnd in Shaft represent two different foreign keys. Therefore you either need two collections in Coupling or you can relate the existing property Coupling.Shafts to either FirstEnd or SecondEnd but not to both. The other reference would refer to an "invisible" not exposed navigation collection in Coupling. (This is what will happen with the mapping in your own answer: EF will take the second mapping block that overwrites the first one, create a relationship between SecondEnd and Shafts and then another relationship between FirstEnd and a not exposed relationship end in Coupling, not Shafts again.)
The solution with two collections - which makes more sense in my opinion - would look like this:
public class Coupling
{
public int Id { get; set; }
public virtual ICollection<Shaft> ShaftsWithFirstEndHere { get; set; }
public virtual ICollection<Shaft> ShaftsWithSecondEndHere { get; set; }
}
And this mapping:
modelBuilder.Entity<Coupling>()
.HasMany(x => x.ShaftsWithFirstEndHere)
.WithOptional(x => x.FirstEnd);
modelBuilder.Entity<Coupling>()
.HasMany(x => x.ShaftsWithSecondEndHere)
.WithOptional(x => x.SecondEnd);
You can create a readonly and not mapped helper property to concatenate the two collections togother to one collection, but this concatenation will happen in memory after the two navigation collections already have been loaded:
public class Coupling
{
public int Id { get; set; }
public virtual ICollection<Shaft> ShaftsWithFirstEndHere { get; set; }
public virtual ICollection<Shaft> ShaftsWithSecondEndHere { get; set; }
// not mapped to DB because it has only a getter = readonly
public IEnumerable<Shaft> Shafts
{
get { return ShaftsWithFirstEndHere.Concat(ShaftsWithSecondEndHere); }
}
}
There is no kind of mapping which would do such a concatenation automatically. Be aware that a navigation collection property in a one-to-many relationship is just the result of a query by a foreign key in the dependent table (= Shaft in your example). The foreign key which is used to populate a collection (by using Include for example or when lazy loading is triggered) is well defined by the relationship mapping and it is only one key - either the key for FirstEnd or the key for SecondEnd but not both. What you are trying to achieve is the combined concatenated result of two queries by two different foreign keys. And that's not possible with relationship mapping.

Resources