I have seen similar questions to this; but none quite the same; and none have helped me. I want the migration to use a different name for the column than I have for the property in my class. On built-in types, I am able to do this with [Column("newName")]. However, this doesn't work when I want a foreign key to another class.
In other words, this works just fine:
[Column("NameInDB")]
public string NameInCode { get; set; }
But this doesn't work at all:
[Column("Employee_Id")]
public virtual Employee Owner { get; set; }
In the second case, the migration still creates the column as Owner_Id; it completely ignores the Column annotation. Is there somewhere that it says that the Column annotation only works for built-in types? I couldn't find anything about that.
I know that it is possible to use the [ForeignKey] annotation to do this, but if I do, I have to have an extra property in my code that I don't want:
[ForeignKey("Employee_Id")]
public virtual Employee Owner { get; set; }
public int Employee_Id { get; set; }
I don't want to do that because the Employee_Id property is redundant in that case; I'd rather just use the Owner property. Is there a way around this, or a good reason that [Column] seems to be ignored?
public virtual Employee Owner { get; set; } is not mapped to DB, it is not represented in database. It populated by Entity Framework automatically for your convenience. Employee_Id - this is what is stored in DB. Entity Framework uses Employee_Id field to create Owner object. So, Emplyee_Id is not redundant in that case, it is mandatory and it has physical representation in DB, but Owner field is logical part of the class, managed by Entity Framework and not have it's column in DB. Makes sense?
Related
before you link to another post, i am using migrations and all that i can find don't use the way i have to do it.
first this is homework,
second here is a link to a google drive with the "full" project project fill stuff that was given to help, and a word doc with specifications(but the last one is not as important)
so on to the problem i am tring to do my homework the package manager says this "The entity type 'Categories' requires a primary key to be defined. If you intended to use a keyless entity type call 'HasNoKey()'." almost no matter what i do. i can get it to stop but then the database is not actual made at all.
my teacher is not responing to my emails and the other students in my class that have responed have the same issue, and this is the very beginning of the project and for the last few days i have been stuck here so please help.
i will add edit as questions get asked, i am panicking on getting this done in time so i don't know what is important or not.
First of all, double check you actually set PrimaryKey on your Database table. Then use [Key] attribute from System.ComponentModel.DataAnnotations namespace.
public class Categories
{
[Key]
public string CategoryId { get; set; }
public string Name { get; set; }
}
And also, next time, make sure your ID fields are either numeric or Guid and auto generated by database identity specification.. string Ids are slow for querying db records and to index tables.
Must tell model CategoryId is key. Best to use int as type.
[Key]
public int CategoryId { get; set; }
Given an example structure as below, Entity Framework doesn't recognise the base Entity inheritance, and thus doesn't map it as a TPT Inheritance between User and Entity.
// Where DbSet<User> Users { get; set; } is used
public class User : User<int> { }
public class User<TTest> : Entity {
public TTest Whatever { get; set; }
}
public abstract class Entity {
public int EntityId { get; set; }
}
I believe this is because EF will only look at the first level inheritance structure and never see the Entity as the base class, just that it has its properties.
So my question is, how can I force EF to recognise that Entity is indeed the base class? Just defining that User has a ForeignKey to Entity in the migration obviously isn't enough, as it still doesn't create that underlying row.
Bonus points: I've already noted that I can't go another level down (ie. Employee : User), but if you'd like to correct me on that I'll be forever in your debt also.
Update: Repro available here on github.com.
Update2: Gert Arnold's theory about not being able to map generic classes and thus breaking the chain unfortunately generated the same migration wherein User didn't fall through to Entity.
Update3: I can confirm that the stricken out "bonus" above does indeed work, when User maps correctly. The inheritance structure of Entity : User : Employee works when all 3 are tables, it is obviously not working when User can't even map back to Entity, which I believe now to be a bug in EF.
You need to add a DbSet for each type that you want EntityFramework to add a table for, like this:
public virtual DbSet<Entity> Entities { get; set; }
public virtual DbSet<User> Users { get; set; }
In EF 6 (code first), is it possible to have a navigation property set-up without enforcing a referential integrity constraint?
For example:
public class Person{
public IList<Pet> Pets { get; set; }
}
public class Pet{
public int OwnerId { get; set; }
public Person Owner { get; set; }
}
So in the example above I'd like to be able to add a Pet with an OwnerId, even if that owner does not exist in the Owners table.
Thanks
Matt
You can define the relationship using the fluent API.
modelBuilder.Entity<Pet>
.hasOptional(p => p.Owner)
.willCascadeOnDelete(false);
This will configure the relational property as optional, and will ensure that cascade delete does not take effect. You can create a Pet without an Owner, and deleting an Owner will not delete the associated Pets.
However you cannot assign Pet.OwnerId to an OwnerId that doesn't exist in the Owner table. If you truly need to have some way of tracking invalid OwnerId values, you either need to have a separate property which you manually update with an arbitrary value, or you would need to define these objects without using a navigation property, and perform your lookups manually.
It would be an exceptional situation where you would need to supply an arbitrary value for OwnerId that doesn't match the Owner table; In 99% of all cases, an optional relationship which accepts a valid OwnerId or null is all that is necessary.
The OwnerId property isn't actually necessary on the Pet object, but if it is present, it should be set to int? to be nullable.
Short Answer: Don't use EF. The whole point of Object Relational Mappers is to ensure you have valid data as well as help with retrieving/persisting it
All you really want is some sort of mapper.
Long Answer: Curious myself
I have two tables named as Profile and ProfileHistory.
Each record in ProfileHistory has to belong to a profile in Profile table, so there is a foreign key relation between two tables. Besides, in ProfileHistory table, there is a column named as ManagerId which also relates to Profile table with foreign key relation.
Profile table structure
Id int primary key
....
....
ProfileHistory table structure
Id int primary key
ProfileId int foreign key to Profile table
ManagerId int foreign key to Profile table
....
My question is:
Since currently I only know this, I am creating my entity model from database.
Model and therefore entity classes are created with navigation properties in
ProfileHistory entity like following:
public virtual Profile Profile { get; set; }
public virtual Profile Profile1 { get; set; }
It is so confusing. Because it is not clear which navigation property for which relation.
Even it is worse if I have more relations between two tables. navigation property names are becoming Profile, Profile1, Profile2, etc.
I was expecting to have the name of the navigation properties related with its foreign key relations.
How can I make my navigation property names something that related to its foreign key relation, in my case "from Profile1 to ProfileManager" ?
Thank in advance for your kind helps.
Muharrem
You can always rename the properties in model diagram. The name can be found in Properties window when you click on a navigation property.
I haven't tested it, but you can map a property to a column using an attribute:
[Column(“BlogDescription", TypeName="ntext")]
public virtual Profile Profile { get; set; }
[Column("Profile1", TypeName="int")]
public virtual Profile ProfileManager { get; set; }
Change the type and the name of the column as it is in the database.
The way I usually solve this is to add properties through partial classes that better represent what I'm after. This way if I need to delete the entity from the diagram and re-add it, I don't lose any renamed columns from the model.
The downside to this is that you need to remember that you cannot use them in Queries because EF won't know how to translate it into a SQL query. But if you've already got your Profile object, it's a lot easier to access myProfile.Manager than myProfile.Profile1.
So, for example, if EF created this for you:
public partial class ProfileHistory
{
public virtual Profile Profile { get; set; }
public virtual Profile Profile1 { get; set; }
}
I would end up creating a partial class like this to re-map the columns:
public partial class ProfileHistory
{
public Profile Manager
{
get
{
return this.Profile1;
}
set
{
this.Profile1 = value;
}
}
}
I did face the same problem some time ago. Well, it is even bigger then just confusing names. If you have navigation properties to another table, like Profile, Profile1, Profile2, next you delete/edit the corresponding foreign keys you may end up having those mixed. And if you used EntitySQL to query data you'll end up having bugs because of incorrect data retrieved/wrong table join conditions...
What I did was changing the t4 template and modified the way properties are generated. When property code text is being written you have the information about association and foreign key related to it. Foreign key names are unique in database and I named those with following pattern
FK_[Table]_[Meaning]
...
FK_ProfileHistory_InitialProfile
FK_ProfileHistory_UpdatedProfile
Next, having this information, I named the properties with the [Meaning] part of the foreign key name.
I have two entities and there are their POCO:
public class DocumentColumn
{
public virtual long Id { get; set; }
public virtual string Name { get; set; }
public virtual long? DocumentTypeId { get; set; }
}
public class DocumentType {
public virtual long Id { get; set; }
public virtual string Name { get; set; }
}
There is a relation between those two entities. In the db the relation called:FK_T_DOCUMENT_COLUMN_T_DOCUMENT_TYPE.
When I do:
DocumentColumns.Where(x => x.DocumentTypeId == documentTypeId).ToList();
I get the exception:
{"Metadata information for the relationship 'MyModel.FK_T_DOCUMENT_COLUMN_T_DOCUMENT_TYPE' could not be retrieved. If mapping attributes are used, make sure that the EdmRelationshipAttribute for the relationship has been defined in the assembly. When using convention-based mapping, metadata information for relationships between detached entities cannot be determined.\r\nParameter name: relationshipName"}
I tryed to remove the relationship and the DocumentColumn table and reload them but the code still throws the exception.
Whet does this exception means and how can I solve it?
EDIT:
The exception happens also If I do DocumentColumns.ToList();
(Presuming you are talking about Code First ....)
There is no information in either class to let CF know that there is a relationship between them. It doesn't matter that the database has the info. Entity Framework needs to have a clue about the relationship. You provide only a property with an integer. CF cannot infer a relationship. You must have something in one class or another that provides type or another. This is not a database. It's a data model. Very different things.
But that's not all. I'm guessing that this is a one to many relationship. You could either put a List property into the Document class or a Document property in the DocumentColumn class. If you only do the latter, CF and EF will NOT know about the 1:. It will presume a 1:1 (that is if you leave DocumentId integer in there, otherwise it will presume a 1:0..1). However, I think you could get away with this and then just configure the multiplicity (1:) in fluent API.
UPDATE...reading your question again, I think you are using an EDMX and designer not code first. What are you using to create your POCO classes? Are you doing code gen from the EDMX or just writing the classes. I still think the lack of a navigation property in at least ONE of the types might be the cause of the problem. The ERROR message does not suggest that...I'm only coming to this conclusion by looking at the classes and inferring my understanding of how EF works with the metadata. I could be barking up the wrong tree. FWIW, I have asked the team if they are familiar with this exception and can provide some idea of what pattern would create it. It's pretty bizarre. :)
It seems odd to me that you are using EF with a defined relationship and you are not using the related property. Can you not do:
DocumentColumns.Where(x=>x.DocumentType.Id == documentTypeId).ToList();
This is what I would expect to see in this instance.