I am doing code first and using a Table-per-type design. I am getting the following error when I extend the second object to multiple tables:
A value shared across entities or associations is generated in more than one location. Check that mapping does not split an EntityKey to multiple store-generated columns.
My database looks like:
Thanks for the up-vote, editing to add my picture:
The POCO for the project looks like:
public abstract class Project {
public int ProjectID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public virtual ICollection<Tag> Tags { get; set; }
public virtual ICollection<LocationElement> LocationElements { get; set; }
public abstract string getProjectIdentifier();
}
And for a Location Element:
public enum HowObtainedCodes {
Provided = 1,
Estimated = 2,
Summarized = 3
}
public abstract class LocationElement {
public int LocationElementID { get; set; }
public int ProjectID { get; set; }
public HowObtainedCodes HowObtainedCodeID { get; set; }
}
And for a point:
[Table("ProvidedPoints")]
public class ProvidedPoint : LocationElement {
public double Lat { get; set; }
public double Long { get; set; }
public string Description { get; set; }
}
The link from projects (abstract) to scientific licences works fine, and my objects load / persist as expected. Further I can add LocationElements object in if I make it not abstract. As soon as I extend LocationElements and try to save a ProvidedPoint object I get the above message. My first thought was that the LocationElementID on ProvidedPoints was set as an Identity column, but this was not the case.
My question is: Am I doing something unexpected by trying to link two TPT objects together in this way? Am I missing something else?
As noted by #leppie above, I had to decorate the LocationElement class with the annotation [Table("LocationElements")], which immediately fixed the problem. My understanding with EF was that this was not necessary with the base table for a TPT design, and further I had not done it on the Project / ScientificLicence pair (that is, I only decorated the ScientificLicence object).
I am assuming this has something to do with the way LocationElements are added/persisted when I save a new Project object. If anyone has any additional insight I would love to know more.
Hope this helps someone else and a big thank you to leppie!
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
I have an Article entity in my database:
public class Article
{
public Guid Id { get; set; }
public string Heading { get; set; }
public string Author { get; set; }
public string Content { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
public int ViewsCount { get; set; }
public ImageData Image { get; set; }
public IEnumerable<Comment> Comments { get; set; }
}
For the creation I have ArticleInputModel, and for displaying the details view, I have ArticleDetailsModel, and for update I have ArticleUpdateModel (etc....)
However those models have the same properties.
Should I separate this much if it means repetitions of code?
I try to follow SRP but this seems like is breaking DRY principle?
Am I overlooking something and what?
Should I separate this much if it means repetitions of code?
Usually, you can identify three situations with potentially different sets of properties when working with model classes (Data Transfer Objects; DTOs) for a single entity:
entity creation
entity reading (displaying, viewing)
entity updating
However, there may be many more subtypes — e.g. different ways to create or update an entity, partial vs. full update, various kinds of displays, e.g. full view, some kind of partial views, view of an entity in a list etc.
It does make sense to have a system in constructing DTOs, such that you differentiate between the create, read (view), update DTOs in respect to your Create, Read, Update operations. You can see a clear parallel between such DTOs and CRU(D) operations (there's typically no DTO for the Delete operation).
Regardless of the particular naming you use, such categorizations help future maintainability of your code: if, in the future, you need to introduce a property that may not be set during entity creation, but can be altered during an update, or vice versa, it is easy to do without extensive changes to unrelated parts of code, e.g. you change the updating path only, but avoid changing the creating path.
I try to follow SRP but this seems like is breaking DRY principle?
Providing the model (DTOs) classes are semantically different, then I don't see this as a violation of DRY. However, this may be subjective.
Think of DTOs as secondary objects. The primary declaration is the database entity, which is part of your data model. The various views of such an entity in the form of DTOs are dependent on this entity declaration. As long as you keep it to a simple public SomeType PropName { get; set; } in the DTOs, it is not a violation of DRY you couldn't live with. In addition, it makes sense to e.g. keep comments explaining various properties in entity declarations only, and not duplicate them into DTOs (unless you have to generate some API docs, but that's solvable with <inheritdoc/> as well). What's important, is the clear distinction between entities and DTOs and their roles.
If you're creating a new instance of an Article, what is it's Id?
Or as a more clear example, what will it's UpdatedOn date be?
How do you update something that doesn't exist yet?
One other issue you might come across very quickly is how are you going to return a list of all the articles by a particular Author?
In the Article table you should be storing Author as an Id linking as a foreign key to the Author table (assuming there can only be a single Author).
If your article table now looks like this...
public class Article
{
public Guid Id { get; set; }
public string Heading { get; set; }
public Id Author { get; set; }
public string Content { get; set; }
public DateTime CreatedOn { get; set; }
public DateTime UpdatedOn { get; set; }
public int ViewsCount { get; set; }
public ImageData Image { get; set; }
public IEnumerable<Comment> Comments { get; set; }
}
...you might begin to see where separate ViewModels/DTOs come into play.
Create
public class CreateArticle
{
public string Heading { get; set; }
public IEnumerable { get; set; }
public string Content { get; set; }
public string Image { get; set; }
}
You're creating a new Article so will probably be inserting an auto generated Guid as the key. You'll also be fairly likely to be taking the current date/time as the CreatedOn date. Author would come from a lookup list of some description so you'd need to pass some sort of list into the View (simplified as IEnumerable above). The image is most likely going to be supplied from a path to the image location so you'd maybe want to display as a text box.
Add
public class AddArticle
{
public string Heading { get; set; }
public Id Author { get; set; }
public string Content { get; set; }
public ImageData Image { get; set; }
}
When you've filled in your Create form, you now want to add it to the db. In this case your DTO needs to add data in the format the db expects. So you'd now be passing the selected Author Id and maybe the ImageData after some processing magic elsewhere.
You still don't need an Article Id or CreatedOn as these will be added once this DTO has validated.
Details and View
Hopefully you're now seeing the slight differences that make the ViewModel a valuable asset. You might also require something like the following to show the details of an Article as opposed to viewing the Article itself:
public class DetailOfArticle
{
public Guid Id { get; set; }
public string Heading { get; set; }
public Author Author { get; set; }
public string Content { get; set; }
public string CreatedOn { get; set; }
public string UpdatedOn { get; set; }
public int ViewsCount { get; set; }
}
public class ViewArticle
{
public Guid Id { get; set; }
public string Heading { get; set; }
public string Author { get; set; }
public string Content { get; set; }
public string CreatedOn { get; set; }
public string UpdatedOn { get; set; }
public int ViewsCount { get; set; }
public ImageData Image { get; set; }
public IEnumerable<Comment> Comments { get; set; }
}
Notice that the details might pass in an Author entity so that you can supply more information (this could also be exploded out into separate properties). You might also want to pass the date (and/or time) as a string after formatting etc.
The Article detail probably wouldn't need the comments as it's essentially the meta-data about the Article whereas the Article view is the Article as you'd want to present it for reading.
I'm trying to make an inheritance TPT Entity Framework to build tables for each type.i searched the site and saw all but the code i based by them will only build one table for all
here is my classes
public class Foo
{
[Key]
public int Id { get; set; }
public int MainFooProp { get; set; }
}
public class FooA : Foo
{
public int FooAProp { get; set; }
}
public class FooB : Foo
{
public int FoobProp { get; set; }
}
and my Context is
public DbSet<FooA> FooAs { get; set; }
public DbSet<FooB> FooBs { get; set; }
and in modelBuilder i used
modelBuilder.Entity<Foo>().ToTable("Foos")
.Map<FooA>(fa => fa.Requires("FooType").HasValue(1))
.Map<FooB>(fb => fb.Requires("FooType").HasValue(2));
i want it to build one table for each including Foo
it should make something like this diagram
diagram of what i really want
but unfortunately it only makes one table including all properties.
sorry guys but i really desperate to make it work
Looks like the answer is removed so I the solution I used
modelBuilder.Entity<Foo>().ToTable("Foos")
modelBuilder.Entity<FooA>().ToTable("Foos")
modelBuilder.Entity<FooB>().ToTable("Foos")1
INTRODUCTION
I am trying to learn how to use Entity framework on my own ( Code First approach ) by solving a small task that I have designed myself.
In order to understand my problem, you must be familiar with the content of the task I mentioned, so i will provide relevant information in the below section.
RELEVANT INFORMATION:
I have invented the following data model for a small quiz:
Each player answers 10 questions.
Each question has 3 possible answers, user chooses one (by clicking on the radio button, for example)
Only one answer is correct, other 2 are wrong.
PROBLEM:
I got stuck at implementing POCOs, so I need your advice on how to implement them properly.
I believe I did the basic stuff properly and that my main problem is in implementing navigational properties.
MY EFFORTS TO SOLVE THIS:
I do not have much to show. Still, my habit is to always show everything I have, in order to ease the task of the community.
Therefore, these are my unfinished POCOs:
public class Answer
{
public int AnswerId { get; set; }
public string TextOfTheAnswer { get; set; }
}
public class Question
{
public int QuestionId { get; set; }
public string TextOfTheQuestion { get; set; }
}
public class Player
{
public int PlayerId { get; set; }
public string Name { get; set; }
}
During writing of this post, I am using Google to learn as much as possible to solve my problem. If I make any headway I will update this post accordingly.
QUESTIONS:
How should I implement navigational properties to mirror the relationships from my data model?
Additionally, is there a way for me to enforce some of the imposed restrictions ( each question has 3 options; player answers on 10 different questions; only one answer is correct answer to the question; and so on...)?
I apologize if these questions may sound trivial to someone experienced. I am just beginning with C# and Entity framework, and can not wait to write anything that works. I hope you can all relate. Thank you for your understanding.
As for the navigational properties, here's something to get you started (let me know if there's something I have missed):
public class Answer
{
[Key]
public int AnswerId { get; set; }
public string TextOfTheAnswer { get; set; }
public int QuestionId{get;set;}
[ForeignKey(nameof(QuestionId))]
public virtual Question Question{get;set;}
}
public class Question
{
[Key]
public int QuestionId { get; set; }
public string TextOfTheQuestion { get; set; }
public virtual ICollection<Answer> Answers{get;set;}
public int CorrectAnswerId{get;set;}
[ForeignKey(nameof(CorrectAnswerId))]
public virtual Answer CorrectAnswer{get;set;}
}
public class SessionQuestion
{
[Key]
public int SessionQuestionId { get; set; }
public int QuestionId{get;set;}
[ForeignKey(nameof(QuestionId))]
public virtual Question Question{get;set;}
public int PlayerAnswerId{get;set;}
[ForeignKey(nameof(PlayerAnswerId))]
public virtual Answer PlayerAnswer{get;set;}
public int TriviaSessionId { get; set; }
[ForeignKey(nameof(TriviaSessionId))]
public virtual TriviaSession TriviaSession{ get; set; }
}
public class TriviaSession
{
[Key]
public int SessionId { get; set; }
public int PlayerId { get; set; }
[ForeignKey(nameof(PlayerId))]
public virtual Player Player{ get; set; }
public virtual ICollection<SessionQuestion> SessionQuestions{get;set;}
}
public class Player
{
[Key]
public int PlayerId { get; set; }
public string Name { get; set; }
public virtual ICollection<TriviaSession> TriviaSessions{get;set;}
}
Basically, EF creates subclasses of your classes at runtime, so leaving the navigation properties virtual lets the EF classes override them and obtain the reference according to the key which resides in the property whose name is the string passed to the ForeignKey attribute's constructor (quite a mouthful, huh?).
One to many navigation is easily created via declaring a virtual generic ICollection property.
Note that this model enforces the fact that only one question is correct- by design. As for the other restrictions, it sounds like business logic rules, not something you should have your data layer enforce.
I have two entities with exactly the same properties:
public class Oil
{
public Guid Id { get; set; }
public string Title { get; set; }
public int Price { get; set; }
public int Ammount { get; set; }
}
public class Filter
{
public Guid Id { get; set; }
public string Title { get; set; }
public int Price { get; set; }
public int Ammount { get; set; }
}
Questions:
1) Can I somehow store them in one table? If so, than how?
2) Or should I implement inheritance? And what type then?
Edits:
In my case these two entities are just the same, they will not have any different properties in the future.
I implemented Table-per-Hierarchy approach, but there is another issue
(I have another type that has collections of oils and filters):
public class Warehouse
{
public Guid Id { get; set; }
public ICollection<Filter> Filters { get; set; }
public ICollection<Oil> Oils { get; set; }
}
So, when I create database, I get Warehouse_Id and Warehouse_Id1 fields in it. I don't want the Oil and Filter classes to have Warehouse property in them, how can I get just one field for Warehouse id in the db table?
If I include WarehouseId as a property in OilFilterBase class I will get 3 warehouse_id in the database table.
p.s. I also have DbSet<Oil> and DbSet<Filter> in my Context and don't have DbSet<OilFilterBase>.
It's hard to say what's best without knowing more about your requirements. What makes these two entities different? If they perform different functions and just happen to have the same properties, then it would probably be a good idea to store them in separate tables; that makes the most sense conceptually, and it would make things much easier if, say, you decided you wanted to add additional properties to one of them in the future.
On the other hand, if they're really the same at every level, it's also worth asking if you really need two different entity types to store them.
For the middle ground where the two classes serve related purposes but also differ in some ways, then yes, some form of inheritance might be a good approach -- either having one entity type derive from the other, or creating a new common base type and having both entities derive from that.
If you decide this is the best approach, then it looks like a good candidate for Table-per-Hierarchy mapping. You could restructure your code something like this:
public abstract class OilFilterBase
{
public Guid Id { get; set; }
public string Title { get; set; }
public int Price { get; set; }
public int Amount { get; set; }
}
public class Oil : OilFilterBase
{
}
public class Filter : OilFilterBase
{
}
...and then the Entity Framework will, by default, create a single table with an automatically-generated discriminator column, and store all instances of both entity types in that table.
If you decide that either of those entity types should have additional fields, then you could look at some of the other inheritance options, like Table-per-Type, that create separate but related tables for each entity type.
The first thing to do is decide how these classes fit together conceptually, and then figure out the best way to implement that in EF terms. If you can give more information about what these entities are and how they work, it'll be easier for people here to give good advice.
Response to Edits:
I think what's happening with the extra columns (Warehouse_Id and Warehouse_Id1) is this:
Because you're setting up the relationships for Oil and Filter separately, it's not comfortable assuming you want to use the base class's WarehouseId property as the foreign key -- what if you only wanted to set up that relationship for Oil and not Filter? It shouldn't be writing to the base class column in that case. So, it decides to create new properties instead.
Fortunately, you can use the [ForeignKey()] attribute (or the fluent API) to tell it what you really want, like this:
using System.ComponentModel.DataAnnotations.Schema;
public abstract class OilFilterBase
{
public Guid Id { get; set; }
public string Title { get; set; }
public int Price { get; set; }
public int Amount { get; set; }
public Guid WarehouseId { get; set; }
}
public class Oil : OilFilterBase
{
}
public class Filter : OilFilterBase
{
}
public class Warehouse
{
public Guid Id { get; set; }
[ForeignKey("WarehouseId")]
public virtual ICollection<Filter> Filters { get; set; }
[ForeignKey("WarehouseId")]
public virtual ICollection<Oil> Oils { get; set; }
}
Also, I think you'll need to include a DbSet<OilFilterBase> (in addition to DbSet<Oil> and DbSet<Filter>) in your context in order to get Table-per-Hierarchy inheritance to work -- try it and see.
Good luck!
I've got a basic grip of the latest version of EF code first via this tutorial - http://www.asp.net/mvc/tutorials/getting-started-with-mvc3-part4-cs but I'm slightly confused about one aspect and wondering if anybody could shed light on it? To explain - there's a class called "Site" which I want to have a field called "HomePageId" which should then map to the "SitePage" object with that Id. Seems simple enough? But when EF creates the Db and the relationships it doesn't seem to understand this. I'm sure it's something I'm doing wrong - here's the code:
public class Site
{
public int SiteId { get; set; }
public string SiteName { get; set; }
public string SiteUrlPortion { get; set; }
// Relationship - SitePages
public virtual ICollection<SitePage> SitePages { get; set; }
// Relationship - HomePage
public int HomePageId { get; set; }
public virtual SitePage HomePage { get; set; }
}
public class SitePage
{
public int SitePageId { get; set; }
public string SitePageTitle { get; set; }
public string SitePageUrlPortion { get; set; }
// Relationship - Site
public int SiteId { get; set; }
public virtual Site Site { get; set; }
}
The "SitePage" class generates the relationship back to "Site" as you would expect. But what I've got in terms of columns in both tables not only doesn't make sense but the relationship from the code-side of things doesn't work as expected. (Eg when I give the "Site" a "HomePageId" the site's "HomePage" is null.
Obviously there's little out there in terms of documentation because this is still in development, but just wondering if anybody had any ideas? Do I need to start decorating the properties with Attributes? Or am I asking it to understand something that it never will?!
Thanks to all in advance. I'll persevere anyway and post back anything I find obviously.
Rob
try marking your HomePage property with a ForeignKey attribute like this
[Foreignkey("HomePageId")]
public virtual SitePage HomePage { get; set; }
you could also use the fluent configuration but don't remember that offhand
It is probably a limitation in EF. That EF can only handle one relationship between 2 tables.
You have 2 relationships between the tables, to the list of site pages and to the home page.
try removing this line:
public virtual SitePage HomePage { get; set; }
You still have the homepageid, so in a way this information was redundant.