I am using EF6 and in my customer table I like to have a column that is of type GUID and is unique. Doesn't have to be a primary. What I want to use this for, is to allow users to unsubscribe from emails. So I though every customer has a GUID under say UnsubscribeEmailGuid column and I send this in a form of a link, when they click it, I can figure out which customer it is, and set their preference to unsubscribe.
Now how can I using EF, define this column and make sure it has some value when a customer is created. I sort of tried:
public Guid UnsubscribeEmailGuid{ get; set; }
and:
Property(c => c.UnsubscribeEmailGuid)
.IsRequired()
.HasColumnAnnotation(IndexAnnotation.AnnotationName, new IndexAnnotation(new IndexAttribute {IsUnique = true}));
But it creates the customer with Guid 00000000-0000-0000-0000-000000000000.
I am pretty sure I have to do something to the above setter property but my brain has stopped working!
Can someone please give me a nudge? Or maybe I am completely on the wrong track?
Thanks.
try with this example, you have to initialize the object, for example i have the user class, and the property type GUID, so:
[Table( "users" )]
public class user{
[Index(IsUnique = true)]
public Guid UnsubscribeEmailGuid{ get; set; }
public user(){
this.UnsubscribeEmailGuid = new Guid();
}
}
then, when you create a new entity of user, the constructor asign a value in UnsubscribeEmailGuid property. aditional to this you can use a DataAnotation for unique index.
Related
Challenge in EF6:
how to check Id of resulting row in the database after running this (esentially adding an entity record):
repository.Add(myEntity1);
...and use that id to add the second entity which has property X = to the id of the first entity?
use that id to add the second entity which has property X = to the id of the first entity?
repository.Add(myEntity2);
Right now there is no linkage between entity 1 and entity 2 because i don;t know how to save the id (automatically generated by ef) after first add
... and preserve it for adding it as a fk in the second entity?
Thanks a lot
You could try this following after your call to SaveChanges:
myEntity2.X = myEntity1.Id;
Then call SaveChanges again. This doesn't really utilise the power of Entity Framework, however, which is in managing relationships between entities. If your class was defined something like this:
public class MyEntity
{
[Key]
public int Id { get; set; }
[ForeignKey(nameof(RelatedEntity))]
public int RelatedEntityId { get; set; }
public MyEntity RelatedEntity { get; set; }
}
You could add your entities something like the following, and the Id/foreign key matching would be handled for you after calling SaveChanges:
myEntity1.RelatedEntity = myEntity2;
This is a fairly general solution, so if you'd like something more specific then you will need to include more details in your question.
You can read more about configuring Entity Framework relationships here.
I have two entities:
//The master table/entity
[TABLE("POSITIONS")]
public class Position{
[Key,Column("POSITIONID")]
public int PositionId{get;set;}
[Column("POSITIONNAME")]
public string PositionName{get;set;}
}
//The detail table/entity
[TABLE("SLAVE_POSITIONS")]
public class SlavePosition{
[Key,Column("MASTERPOSID",Order=0)]
public int MasterPosId{get;set;}
[KEY,Column("SLAVEPOSID",Order=1)]
public string SlavePosId{get;set;}
[ForeignKey("MasterPosId")]
public virtual Position MasterPosition {get;set;}
[ForeignKey("SlavePosId")]
public virtual Position SlavePosition {get;set;}
}
In the SlavePosition, as you can see, there two columns over which this entity is in FK relationship with Position. This layout works great. Now I also need to add this collection property to Position entity:
public virtual ICollection<SlavePosition> SlavePositions{get;set;}
But apparently EF gets confused and I get {"ORA-00904: \"Extent1\".\"Position_PositionId\": invalid identifier"} error.
If I declare it like this:
[ForeignKey("SlavePositionId")]
public virtual ICollection<SlavePosition> SlavePositions { get; set; }
and then fetch a Position with PositionId =1 like this:
Position pos= dbContext.Positions.SingleOrDefault(x=>x.PositionId==1);
I get no error, but I get SlavePOsitions count 0, when it should be 5 because in the database I have 5 rows in the detail table. I am able to confirm this by running the below code:
IEnumerable<SlavePositions> slavePositions= dbcontext.SlavePositions.Where(x=>x.MasterPositionId==1);
I get five SlavePosition.
What should be the correct attribute for this collection property?
I finally figured it out. My mistake was in the referenced dependent property name. Instead of SlavePositionId I should put MasterPositionId.
This makes sense, because the Position entity acts as a master table and in real world Foreign Key relationship is set up on detail tables, not master ones. As there's no property in the dependent entity that has the same name as the PK in the master entity and there're more than one properties that have Foreignkey to the same master entity, EF needs more information.By specifying ForeignKey("MasterPositionId") to the ICollection navigation property, I instruct EF that Dependent end point property should be considered MasterPositionId. So I changed this
[ForeignKey("SlavePositionId")]
public virtual ICollection<SlavePosition> SlavePositions { get; set; }
to this
[ForeignKey("MasterPositionId")]
public virtual ICollection<SlavePosition> SlavePositions { get; set; }
In fact the former one itself is not wrong either, it just does not fit in this situation. But if I wanted to have a collection for MasterPositions this would fit perfectly fine.
I am trying to create an EF6 database where two tables, Addresses and Visits, share the same values as primary keys. Visits, conceptually, is an extension of Addresses. I'm splitting the tables because most of the records in Addresses don't require the fields contained in Visits.
I'm using the code first approach. Here's the relevant code for the Addresses:
public class Address
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ID { get; set; }
[ForeignKey( "ID" )]
public virtual Visit Visit { get; set; }
and for Visits:
public class Visit
{
[Key]
[DatabaseGenerated( DatabaseGeneratedOption.Identity )]
public int ID { get; set; }
[ForeignKey("ID")]
public virtual Address Address { get; set; }
Based on my research, I also needed to include the following in my datacontext's OnModelCreating method:
modelBuilder.Entity<Visit>()
.HasOptional( v => v.Address )
.WithRequired();
Unfortunately, this doesn't work. I can update the database alright, after eliminating scaffolding calls to drop the primary index from Addresses (probably because the add-migration code thinks the primary key is "merely" a foreign key field). But when I run the application I get the following error:
Invalid column name 'Address_ID'.
Invalid column name 'Address_ID'.
From my limited experience with EF6 this looks like someplace deep inside the framework it's expecting there to be fields named 'Address_ID', probably in the Visits table (based on the 'table name'_'field name' naming structure I've seen for other implicitly added fields).
Is what I'm trying to do possible? If so, what am I missing in the configuration?
Additional Info
In trying out bubi's proposed solution, which unfortunately still generates the same error, that I could eliminate the OnModelCreating code and still get functional migration code generated.
Resolution
I finally did what I should've done earlier, which is examine the actual T-SQL code generated by the query which was blowing up. It turns out the problem was not in the Visit/Address linkage, but in a completely separate relationship involving another table. Apparently, somewhere along the way I did something to cause EF to think that other table (Voters) had an Address_ID foreign key field. In reality, the Address/Voter relationship should've been, and originally was, tied to a Voter.AddressID field.
Rather than try to unwind a large number of migrations I opted to blow away the database, blow away the migrations and start from scratch. After recreating the database -- but using bubi's suggestion -- I reloaded the data from backup and, voila, I was back in business.
For the sake of completeness, here's the code I ended up having to put into the OnModelCreating method call to get the Address/Visit relationship to work correctly:
modelBuilder.Entity<Visit>()
.HasRequired( v => v.Address )
.WithRequiredDependent( a => a.Visit );
modelBuilder.Entity<Address>()
.HasRequired( a => a.Visit )
.WithRequiredPrincipal( v => v.Address );
I am a little confused about why I have to use HasRequired in order to be able to use WithRequiredPrincipal/WithRequiredDependent, since not every entry in the Address table has an entry in the Visit table. That would seem to be "optional", not "required". But it appears to work, and maybe the "required" part is just internal to EF's model of the database, not the database itself.
There are 2 problems in the model:
- Only one of the Keys can be autonumbering, the other must get the same Id (this independently by EF).
- A mapping problem.
This model should work.
public class Address
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Description { get; set; }
public virtual Visit Visit { get; set; }
}
public class Visit
{
public Visit()
{
Address = new Address();
}
[Key]
[ForeignKey("Address")]
public int Id { get; set; }
public string Description { get; set; }
public virtual Address Address { get; set; }
}
Example of use
var visit = new Visit
{
Description = "Visit",
Address = {Description = "AddressDescription"}
};
db.Visits.Add(visit);
db.SaveChanges();
In addition to what bubi mentioned, your modelBuilder statement contradicts the model in that it doesn't mention Address.Visit as the inverse property. So it thinks that the property represents a separate relationship and tries to create the Address_ID column for that relationship.
You need to have
modelBuilder.Entity<Visit>()
// from your description sounds like every Visit needs an Address
.HasRequired(v => v.Address )
// need to mention the inverse property here if you have one
.WithOptional(a => a.Visit);
...or just remove the statement completely since you're already using attributes, and EF should be able to figure it out by convention.
Table name: TableStatus The tool produces TableStatu with a variable name of TableStatus. For others, TablePerson it creates TablePerson with variable name TablePersons. With Code First you can remove the pluralizations. I found some snippets for both the Entity.tt and Context.tt to remove/add pluralization when you reverse engineer, but neither seem to have any affect on the output classes and DbContext DbSet names. It may be something simple, but I don't see it.
When you do a database-first model, there is an option to pluralize/singularize entity names. Turn this off and it should solve your problem.
You can use the Table attribute to specify the table name.
[Table("account", Schema = "dbo")]
public class Account
{
[Key]
public int id { get; set; }
public string Email { get; set; }
}
I have a Supplier entity, each Supplier object may reference another Supplier object as its 'parent'.
public class Supplier
{
public int? Id { get; set; }
public virtual Supplier Parent { get; set; }
}
This all works as expected until I attempt to remove the relationship, as in, this supplier no longer has a parent. I can change it from null to a particular supplier and I can set it to a different supplier but setting it to null is not persisted after SaveChanges().
supplier.Parent = null;
The foreign key 'ParentId' in the Supplier table is set as nullable. Explicitly defining the relationship doesn't help.
modelBuilder.Entity<Supplier>().HasOptional(s => s.Parent).WithMany();
I'm sure I'm missing something obvious.
Just found another place in my code where I do the exact same thing (that works) and found this;
// Must access property (trigger lazy-loading) before we can set it to null (Entity Framework bug!!!)
var colour = modelItem.Colour;
modelItem.Colour = null;
Did the same in the new code and it all works.
Instead of just modelBuilder.Entity<Supplier>().HasOptional(s => s.Parent).WithMany(); use the following modelBuilder.Entity<Supplier>().HasOptional(s => s.Parent).WithMany().HasForeignKey(x=>x.ParentId);
Otherwise it has no idea what the foreign key's name is