How do I include an unmapped field in a POCO class - entity-framework

I'm new to the EF and am just experimenting. Can someone tell me if the following is possible. Given a (product) table in the DB like so:
Id Cost DescriptionFK
-- ---- -------------
? ? ?
I want the corresponding POCO class (entity) to appear like:
public class Product
{
public int Id { get; set; }
public decimal Cost { get; set; }
public string Description { get; }
}
Note that the "Description" in the class is a read-only string (no setter), but it's a key in the table. I'm calling a stored procedure to pull this off (converting the key to its corresponding string and returning the above class), but if I now do something like:
// ...
product.Cost = 20;
myContext.SaveChanges();
I get an exception complaining that there's no mapping for the "Description" string. I removed the mapping because it's read-only and I don't need to include the "DescriptionFK" in the class itself. Is there some way to pull this off (POCO only). Thanks very much.

If you are just looking to have the Description property as a calculated field, add [NotMapped] to your the property to explicitly exclude it and then generate the database:
public class Product
{
public int Id { get; set; }
public decimal Cost { get; set; }
[NotMapped]
public string Description { get; }
}

AFAIU, it is not possible.
"You always need at least one navigation property to create a foreign key constraint in the database."
EF Code First foreign key without navigation property

Related

1 to many with composite key as primary key

I tried many different examples here, but i can't seem to figure out what i'm doing wrong.
I have a table with a history table to it. I have removed many of the fields to make it easier to watch. After my migration it works fine if i watch in PHPMyAdmin and watch the primaryKey there.
I want to be able to go context.ProductArtifactDocumentState.Histories so i can get all linked histories.
DBContext
//Composite Key
builder.Entity<ProductArtifactDocumentStateHistory>()
.HasKey(k => new { k.Version, k.ProductArtifactDocumentStateId});
Table
[Table("ProductArtifactDocumentsState")]
public partial class ProductArtifactDocumentState : BaseEntity
{
public virtual ICollection<ProductArtifactDocumentStateHistory> ProductArtifactDocumentStateHistories { get; set; }
}
History Table
[Table("ProductArtifactDocumentsState_History")]
public partial class ProductArtifactDocumentStateHistory
{
[Column("ProductArtifactDocumentStateId")]
public int ProductArtifactDocumentStateId { get; set; }
public virtual ProductArtifactDocumentState ProductArtifactDocumentState { get; set; }
public int Version { get; set; }
}
The error i get:
System.InvalidOperationException: 'The entity type 'ProductArtifactDocumentStateHistory' requires a primary key to be defined. If you intended to use a keyless entity type, call 'HasNoKey' in 'OnModelCreating'. For more information on keyless entity types, see https://go.microsoft.com/fwlink/?linkid=2141943.'
Why do you need all this headache? Are you trying to save 2 bytes on a primary key? But after this all your ef code will be a nightmare. Just add Id field
public partial class ProductArtifactDocumentStateHistory
{
[Key]
public int Id {get; set;}
.....
}

Entity Framework - The property cannot be configured as a navigation property

I'm defining two entities like the following, but a strange behavior is occurring:
[Table("ClientTypes", Schema="dbo")]
public ClientType {
[Key]
public int Id { get; set; }
public string Name { get; set; }
}
[Table("Clients", Schema="dbo")]
public Client {
[Key]
public long Id { get; set; }
[ForeignKey("ClientTypeId")]
public int ClientTypeId { get; set; }
public virtual ClientType ClientType { get; set; }
}
I'm getting the ClientTypeId property filled with some value, but the ClientType object is filled with nothing. Can someone help me with this?
Thank you all!
The ForeignKey attribute as you have it is on the wrong property.
The annotation may be placed on the foreign key property and specify the associated navigation property name, or placed on a navigation property and specify the associated foreign key name.
- source
[ForeignKey("ClientTypeId")] should decorate public virtual ClientType ClientType instead,
or change it to [ForeignKey("ClientType")] and leave it where it is.
Are you eagerly loading the value?
var clients = context.Clients.Include("ClientType").ToList();
When selecting the Client you have to Include the client type
Client cli = (from c in db Clients.Include("ClientType")//or the name of the property
select c).First();
This translates to a left join and selects the data for Client and ClientType.
If you skip the Include the EF will select the data only for the client when execute the statement.
As Mike said if the context is still available the property will be lazy loaded when you access it.

How to correctly build EF5 Code-first model with two or more lists that relate to the same child table?

I have the following models:
public class SomeForm
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public IList<FacilityContactInformation> OriginatingFacilities { get; set; }
public IList<FacilityContactInformation> DestinationFacilities { get; set; }
}
public class FacilityContactInformation
{
public FacilityContactInformation()
{
Id = -1;
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
[MaxLength(50)]
public string Owner { get; set; }
}
I am using automatic migrations to gen and re-gen the database schema.
This generates the error "Foreign key 'FK_dbo.FacilityContactInformations_dbo.SomeForm_SomeForm_Id ' references invalid column 'SomeForm_Id' in referencing table 'FacilityContactInformations'.
Could not create constraint. See previous errors.
I suspect the root cause is that EF tries to generate a FK FK_dbo.FacilityContactInformations_dbo.SomeForm_SomeForm_Id for both lists
Is there any way to keep using automatic migrations, but get this to generate a FK that works? It would seem like the FK should include the list name and generate two properties on FacilityContactInformations OR should generate an intermediate table to join on.
When you have 2 navigational properties that link to the same class, you should override OnModelCreating method of your dbcontext class. Then add this code into the OnModelCreating:
modelBuilder.Entity<SomeForm>
.Hasmany<FacilityContactInformation>(x => x.OriginatingFacilities);
modelBuilder.Entity<SomeForm>
.Hasmany<FacilityContactInformation>(x => x.DestinationFacilities);
This is because EF cannot determine the correct keys if the nav. prop. link to the same class.

Entity Framework 4.1 Table-Per-Type Mapping

I am trying to write a project using the code-first approach and I have run into the following problem
public class BaseType
{
[Key]
public int id { get; set; }
public string description { get; set; }
}
public class Type1 : BaseType
{
public decimal price { get; set; }
}
public class mycontext : DbContext
{
public DbSet<BaseType> basetypes { get; set; }
public DbSet<Type1> type1 { get; set; }
}
when I run the application and I create an object Type1 and use mycontext.type1.ADD(mytype1object); and I look at the database the table for Type one has the correct field but the parent table "basetypes" also has a price field.
Do I have to ignore the field explicitly?
Any suggestions?
By default code first will use TPH (Table Per Hierarchy) inheritance. What this means is that both of your types are being stored in a single table called 'BaseTypes'. You'll notice that it also includes an extra field called 'Discriminator'. EF will store a value in that field to designate which type that each record is.
If you would like your types to be in different tables you'd need to setup your context for TPT (Table Per Type). You can decorate your classes with a Data Annotation with the table name, or you could use the model binder. Below is the data annotation way.
[Table("BaseTypes")]
public class BaseType
{
[Key]
public int id { get; set; }
public string description { get; set; }
}
[Table("Type1s")]
public class Type1 : BaseType
{
public decimal price { get; set; }
}
I cannot reproduce your problem - in fact if I use the same model with EF 4.1 the DB that's generated only has a BaseTypes table that contains both elements of BaseType
and Type1 - the rows with BaseType elements just have a null value as price. So you are not using TPT but TPH currently. To switch to TPT you could annotate your class Type1 or use the fluent API:
[Table("Type1s")]
public class Type1 : BaseType
{
public decimal price { get; set; }
}
Thanks for the input BrokenGlass and ckal. I was tying to user the "Table(Name)" annotation and fluent API and I followed all of the steps and I kept ending up with a table for both BaseTypes and Type1s and the BaseTypes table contained fields for the fields in Type1s.
However, after I went ahead and made table names for each of the remaining classes in my model, I tried it an everything worked.
I am not sure if this was a fluke, or if I found a bug, but everything is working now.
Thanks again for the quick responses.
Sanity Restored .... For Now!!!

Entity Framework POCO Does Not Fit Nicely with Domain Objects

I have taken a model first approach for a project i'm working on. An example of a class relationship is shown as follows, pretty strightforward:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
List<Photo> Photos { get; set; }
}
public class Photo
{
public int Id { get; set; }
public string Path { get; set; }
}
The database schema will roughly be:
--------------
Products Table
--------------
Id int,
Name Varchar
------------
Photos Table
------------
Id int,
Path varchar
ProductId int FK Products.ID
A Product can have Zero or more Photos.
Now when i try to plug is my ORM of choice (Entity Framework V4 - Poco approach) iam forced to map my relationships in the domain model!
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
List<Photo> Photos { get; set; }
}
public class Photo
{
public int Id { get; set; }
public string Path { get; set; }
public int ProductId {get; set; } //Foriegn Key
public Product Proudct {get; set; } //For uni-directional navigation
}
Firstly, i dont need/want uni-directional navigation. I understand this can be deleted. Secondly, I dont want the Foriegn Key declared in the Photos class.
I dont think this is true POCO/persistence ignorance if i must define database properties in the Domain Objects?
Do other ORM's behave this way?
I found the answer. Using the wizard, there is an option to "Include foreign key columns in the model" - Uncheck this box and you will a clean conceptual model without FK.
Make sure Code Generation Strategy is set to none in the properties window.
Why don't you want to have Photo.Product property? If there is no such property, it seems one photo can belong to several products and since database schema should be more complex (with auxiliary table).
The relationships don't have to be two-way, and don't have to be public (if you use true POCOs, not proxy types). You've said quite a bit about what you don't want in your code, but can you be clearer about how you do want to define the relationships? It has to go somewhere. Where would you like to put it? There are many options.