I have an mvc5 application that is connected to a EF database. Some fields in this database are meant to be autogenerated as declared in SQL, but when used in MVC and upon inserting records, the GUID only contains the value of 0 for all records. How can I resolve this? Any help will be appreciated. Thanks.
Model class:
public partial class Store
{
public int StoreID { get; set; }
public int CustomerID { get; set; }
public string StoreName { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public System.Guid StoreUID { get; set; }
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int StoreNumber { get; set; }
public string StoreLogo { get; set; }
public string StoreLogoPath { get; set; }
public string StoreAddress { get; set; }
public string StoreCity { get; set; }
public string StoreRegion { get; set; }
public string StoreCountry { get; set; }
public virtual Customer Customer { get; set; }
}
Both StoreUID and StoreNumber supposed to be autogenerated fields. Below is an example how its supposed to be when a new store is inserted, however currently, storeNumber and StoreUID both just return 0.
You need to add defaults to your database table to generate the fields.
ALTER TABLE [dbo].[Store] ADD DEFAULT (newid()) FOR [StoreUID]
ALTER TABLE [dbo].[Store] ADD DEFAULT (myfuncthatreturnsanint()) FOR [StoreNumber]
This isn't really an Entity Framework feature. EF needs to be aware of these column types to generate the appropriate SQL. What you require is something that's actually achieved from the database. For Model First, I got the auto generated int Id functionality by modifying the T4 template that ships with EF to write the appropriate SQL, but it really is database functionality. StoreNumber is a different case since SQL server only allows one identity column.
For your database, your StoreUID column specification should be:
StoreUID uniqueidentifier not null DEFAULT newid()
You don't specify if you're dealing with model first or code first, or if you're building something new, so you may have to modify your existing table for this.
EDIT
If you're using model first, ensure that in your model the Store Generated Column is set to Identity for the StoreUID value to be server generated. If not, and you're not worried about who/what creates the GUID, then create a default constructor for Store, if you don't already have one. Then in there add StoreUID = Guid.NewGuid();.
For StoreNumber, SQL server doesn't support multiple columns with auto incrementing integers. You'd need to research a number of strategies for inserting it.
A number are listed here and here. Essentially make StoreNumber a function of StoreID with Computed Columns, or use an independent Sequence:
ALTER TABLE Store DROP COLUMN StoreNumber;
GO
ALTER TABLE Store ADD StoreNumber AS StoreID + 550000;
Related
I was wondering why EF tries to add also foreign models.
Example:
public class Category
{
public int Id { get; set; }
public string Name{ get; set; }
}
public class Content
{
public int Id { get; set; }
public string Name{ get; set; }
public Category Category{ get; set; }
}
After creating "Content" using migrations, I have a table that includes the id of category. That's create. So I have three columns: Id, name and the categoryId. Seems EF "knows" that this should be just the primary key of Category, that needs to get stored.
Than I tried to add something with EF.
var cat = new Category {Id = 2, Name = "awesomeCat"})
var addContent = new Content({Name = "test", Category = cat})
Now I want to add a Content by using _context.Add(addContent). I was expecting a single insert into db that uses the name "test" and the categoryId 2. Id will be generated by DB.
But instead EF also tries to add a new Category into the category table.
So I took a deeper look and seems EF "does" not know it already exists and was not maintaining any transactions about the category model.
I gave it another try and used no new category, instead I was loading it before:
var cat = _context.findById("2");
and assigned this one instead. Now EF should know that this one already exists and does not have to add it in category table.
Could it be, that my model is just wrong.
Do I need to use it more like:
public class Content
{
public int Id { get; set; }
public string Name{ get; set; }
public int? CategoryId{ get; set; }
[ForeignKey("CategoryId")]
public Category Category{ get; set; }
}
Won't I get two category references then?
You need to tell EF Core it's a primary key and to generate the key
public class Category
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
}
public class Content
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int Id { get; set; }
public string Name { get; set; }
public Category Category { get; set; }
}
Then you don't need to mark [ForeignKey("CategoryId")], EF Core will turn the object reference into an ID in the database
If I misunderstood your question, ask again :)
EF Core has internal tracking of entities. When you simply new up a category, it's not being tracked. When you add the content, EF will track any related entities as well, which would include your category, which will by default be tracked as "Added". You have a few choices.
Don't "new up" an existing category, but rather, retrieve it from the database. If EF pulls it from the database, then it will be tracked, and will not be added again.
You can explicitly track the category instance you newed up and set it's state to "Unchanged".
_context.Attach(category);
_context.Entry(category).State = EntityState.Unchanged;
_context.Add(content);
The best method is to not deal with the reference property at all, and use an explicit foreign key property. Add a property to your content class:
public int CategoryId { get; set; }
Then, you can simply set this id, instead of the Category prop:
var addContent = new Content { Name = "test", CategoryId = 2 };
EF will backfill the reference property after save.
This is using asp.net core 2.0, EF, visual studio 2017, sql server 2016, and creating a db migration via package manager console using 'add-migration' tool within the Package Manager Console.
I have a simple many-to-many relationship configured as below, 2 tables and a third 'joining table':
public class TblTrack
{
public int ID { get; set; }
...
//Navigation properties
public List<TblProductItem> ProductItems { get; set; }
}
public class TblProduct
{
public int ID { get; set; }
...
//Navigation properties
public List<TblProductItem> ProductItems { get; set; }
}
public class TblProductItem
{
[Key]
[Required]
public int ProductID { get; set; }
[Key]
[Required]
public int TrackID { get; set; }
//Navigation properties
public TblProduct Product { get; set; }
public TblTrack Track { get; set; }
}
This is from the migration (generate in PMC) to create the joining table:
migrationBuilder.AddPrimaryKey(
name: "PK_tbl_ProductItems",
table: "tbl_ProductItems",
columns: new[] { "ProductID", "TrackID" });
migrationBuilder.CreateIndex(
name: "IX_tbl_ProductItems_TrackID",
table: "tbl_ProductItems",
column: "TrackID");
Please could someone explain:
What's the purpose of the index IX_tbl_ProductItems_TrackID?
Why was an index created for TrackID but not for ProductID?
Is there some other setting that determines which indexes will be created in the migration?
By default EF automatically creates Index (non-unique) on each property that is a foreign key reference.
Make sure that EF correctly created relation between TblProduct and TblProductItem(for example in SQL Server by expanding keys) - if not, specify relation explicitly using Fluent Api.
Regarding other setting you can require creating indexes using method in your Context class, but that index should be auto generated if foreign key relation is set.
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<TblProductItem>()
.HasIndex(e => e.TrackID);
}
I'm struggling with the same thing. I found out that if I reversed the order of the keys (using Fluent, however) it would make an index for the second column instead.
So to me, it seems like there's a bug in the framework when using composite keys. It is the ForeignKey annotation that causes the index to be made, but in this process it seems to believe that the primary key is the FIRST column only (in that case, no extra index needed for a "primary key" column), so it only creates an index for the second. But the primary key is composite, so it should probably create an index for the first column too.
A workaround (if you really want the first column to be indexed too) is to do what's suggested in the accepted answer. Should the bug (AFAIK) be fixed later, I don't think it would cause a problem by trying to create an extra index or anything.
Im developing a mvc5 application using CodeFirst approach. Here is the modal class
public class Feeder
{
[Key]
public int FeederId { get; set; }
public string FeederName { get; set; }
public string FeederCode { get; set; }
public DateTime StatusChangeDate { get; set; }
public int CreateBy { get; set; }
public DateTime CreatedDate { get; set; }
public int EditBy { get; set; }
public DateTime EditDate { get; set; }
}
Here for 'FeederCode' i want to generate a string that increments for every record. The string should be like this.
BMK15FEDR00001
Here 'BMK' and 'FEDR' are fixed. But 15(last 2 digits of 2015) will change based on the year. Since this is 2015 it should be 15 and for next year records it's 16. '00001' should increment for every record as 00002, 00003....
I searched for this but couldn't come up with the correct approach. All help appreciated. Thanks!
Why not making it a computed value?
You said that BMK and FEDR are constant, you can extract the year from CreatedDate, and as far as the last part, your FeederId is already set to auto-gen by default so SQL is making that for you.
Now your computed value should be saved as:
`"BMK" + CreatedDate.ToString("yy") + "FEDR" + FeederId;
and this is what you save in the FeederCode value.
Hope that's what you meant.
If u'd also like each year codes to start from 1 again you should set a composite primary key with the other value being the year. and you can also reset the Identity value, you can read here how it's done (part c).
Update regarding the id value:
USE AdventureWorks2012;
GO
DBCC CHECKIDENT ('Person.AddressType', RESEED, 10);
GO
as decirbed in the attached link:
The following example forces the current identity value in the AddressTypeID column in the AddressType table to a value of 10. Because the table has existing rows, the next row inserted will use 11 as the value, that is, the new current increment value defined for the column value plus 1.
If that's not important to you I advice you to just avoid it. if it is you can use it for your needs. the best way to implement this is to trigger a SQL event that each year will reset the auto-identifier.
I'm not sure how to exactly word my question which is probably why I cannot find an example of this anywhere. I'm playing around with MVC4 & EF5 (Web API too) but I'm not sure how to proceed with the Model as I've never really had to do much with them before. I'm doing something around the Periodic Tablet of Elements and I want to make it so that I have a list built for an element with it's electron configuration. However, I'd like to have it just auto number based on the input order. How can I tell EF to auto-increment a field? Basically like a primary key field without that limitation behind it. Here's what I have so far - I'm just not sure how to proceed:
public class Elements
{
public int ElementID { get; set; }
public string Name { get; set; }
public int AtomicNumber { get; set; }
public string Symbol { get; set; }
public virtual Categories Category { get; set; }
public virtual States State { get; set; }
public virtual Occurences Occurence { get; set; }
public virtual ICollection<Configurations> Configuration { get; set; }
}
public class Categories
{
public int CategoryID { get; set; }
public string CategoryName { get; set; }
}
public class States
{
public int StateID { get; set; }
public string StateName { get; set; }
}
public class Occurences
{
public int OccurenceID { get; set; }
public string OccurenceName { get; set; }
}
public class Configurations
{
public int ConfigurationID { get; set; }
public int Order { get; set; }
public int Value { get; set; }
}
Looking above what I'd like is for anytime a value is added to Configurations.Order the value starts at 1 and increases with each new 'row' but only for that specific ElementID.
Does that make sense? I was looking at using Data Annotations but I couldn't find anything that matched other than a Key Field but that'd make each Order a unique number - which I don't want. I feel like I'm not expressing this correctly because of all the stuff I've been looking at to figure it out, so here's a picture! yay!
This very well could be something that is better off from a programmatic standpoint. Even though this data changes once in a blue moon, I wanted to try and do it through EF if possible just so I know how.
Thanks a ton in advance. Also, if you see any other glaring errors, by all means let me know :) I rarely get to work with this side of web dev so I'm sure there's ways to do things better.
How can I tell EF to auto-increment a field?
You can't. Not even for a simple auto-incrementing primary key. Let alone for a field that should increment in relation to other values.
The HasDatabaseGeneratedOption mapping method is not a way to tell EF how to generate key values. It tells EF if and how the database generates values for properties, so EF knows how to respond to that.
So you either have to generate the order numbers in code, or let the database do it (by a trigger, or by mapping CUD actions on Configurations to stored procedures) and tell EF that the database computes the values by HasDatabaseGeneratedOption(DatabaseGeneratedOption.Computed) in the configuration of the Order property.
I have a simple Poco
public virtual short UserID
{
get;
set;
}
[Required]
public virtual string UserName
{
get;
set;
}
public virtual string Password
{
get;
set;
}
public virtual string Email
{
get;
set;
}
Im currently Using Dapper ORM.
Does anyone have a good example of how I would query using dapper ORM to create a drop-down-list?
The query should return Key=UserID and Value=UserName in a list so that I can retrieve the keys and populate the DropDownList.
you can create a class representing the pair:
class SelectItem
{
public long Key {get;set;}
public string Value {get;set;}
}
var list = connection.Query<SelectItem>(" select id Key UserName Value from yourtable",null).ToList();
you use the aliases to map the table fields to the class properties names. I'm supposing your table field names are id and UserName, change them according to your case.
You should also pay attention to the property types, you can have a bad cast exception if they don't match.
ALternatively, you can use the dynamic version:
var list = connection.Query(" select id Key UserName Value from yourtable",null).ToList();
you obtain a list of dynamics each with property named Key and UserName.