Separate identity column CodeFirst mvc - sql

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.

Related

Computed column based on rows from another table

I have the following (simplified) table
public class Door
{
public int Id { get; set; }
public bool Locked { get; set; }
}
Now the problem with this table is that I don't know how long the door has been locked or not. I could add a new DateTime column, but then, if the door was locked, opened and locked again, I wouldn't know exactly when it was locked the first time since that would be overwritten. So I added a new table
public class Locks
{
public int Id { get; set; }
public int DoorId { get; set; }
public virtual Door Door { get; set; }
public DateTime? LockedFrom { get; set; }
public DateTime? LockedTo { get; set; }
}
and added a public Collection<Locks> to my Door table. This is all nice and good and would solve my first problem. However, Door and Door.Locked has been used extensively throughout our code and changing all those queries would be a very large job. So my hope was that I could rewrite Door.Locked to be a computed column. It should collect the entries for that Door from Locks and compare their DateTimes to the current time to find out if the door is locked right now. It is important that this is a computed column (handled on server side) and not a function or calculated parameter in the entity, since that would cause all queries that filters on Door.Locked to be handled in memory (and I have maaany Doors in my db). I would also prefer if Door.Locked could be not nullable, to avoid changing its type to Bool?, and this seems to be possible by making the column persisted. I've seen examples of computed columns in .NET Core where they use entityTypeBuilder.Property(x => x.Locked).HasComputedColumnSql("some sql formula"), but none that do this when the formula depends upon the content of another table.
Conclusion: I want to create a computed column code first that calculates its value using the content of another table.
Thank you!

Linq takes more than 20 seconds to query a table with less than 100 records

Unfortunately I haven't found a good answer for this problem yet. The answers and questions I have seen so far in here are about big tables with a lot of records.
I'm trying to query a table called Tickets with the following code:
var Status = ticketStatusService.GetByName("New");
string StatusID = Status.Id;
var tickets = db.Tickets.Where(e =>
!e.Deleted &&
e.Project == null &&
e.Status != null &&
e.Status.Id == StatusID);
var list = tickets.ToList();
The table currently has less than 100 records, this query takes an average of 22 seconds to execute.
The code first model for it is as follows:
public class Ticket : Base
{
[Key]
[Required]
public Guid Id { get; set; }
[Display(Name = "Date")]
public DateTime RowDate { get; set; } = DateTime.Now;
public bool Deleted { get; set; } = false;
[Index(IsUnique = true)]
public int? Number { get; set; }
[Display(Name = "Ticket Subject")]
public string Subject { get; set; }
[Display(Name = "Notes (Employees Only)")]
public string Notes { get; set; }
[Display(Name = "E-Mail")]
public string From { get; set; }
[Display(Name = "Phone Number")]
public string Phone { get; set; }
[Display(Name = "Secondary Phone Number")]
public string PhoneAlt { get; set; }
[Display(Name = "Client Name")]
public string Name { get; set; }
[Display(Name = "Message")]
public string Messages { get; set; }
[DataType(DataType.DateTime)]
public DateTime? OpenDate { get; set; }
[DataType(DataType.DateTime)]
public DateTime? CloseDate { get; set; }
[DataType(DataType.DateTime)]
public DateTime? AssignedDate { get; set; }
public bool? Origin { get; set; }
public virtual User AssignedUser { get; set; }
public virtual List<TicketFile> TicketFiles { get; set; }
public virtual List<Task> Tasks { get; set; }
public virtual Project Project { get; set; }
public virtual TicketStatus Status { get; set; }
public virtual TicketClosingCategory TicketClosingCategory { get; set; }
public virtual TicketGroup TicketGroup { get; set; }
public virtual TicketPriority TicketPriority { get; set; }
}
Any insight into this issue would be appreciated. Thank you very much!
Edit: Running the same query directly on SQL Server Management Studio also takes very long, about 9 to 11 seconds. So there might be an issue with the table itself.
I see several possible improvements.
For some reason you chose to deviate from the entity framework code fist conventions. One of them is the use of a List instead of an ICollection, another it that you omit to mention the foreign keys.
Use ICollection istead of List
Are you sure that Ticket.TicketFiles[4] has a defined meaning? And what would Ticket.TicketFiles.Insert(4, new TicketFile()) mean?
Better stick to an interface that prohibits usage of functions that have no defined meaning. Use ICollection<TicketFile>. This way you'll have only functions that have a proper meaning in the context of a database. Besides it gives entity framework the freedom to chose the most efficient collection type to execute its queries.
Let your classes represent the tables
Let your classes just be POCOs. Don't add any functionality that is not in your tables.
In entity framework the columns of a table are represented by non-virtual properties. The virtual properties represent the relations between the tables (one-to-many, many-to-many, ...)
Let entity framework decide what's the most efficient to initialize the data in your sequences. Don't use a constructor where you create a List, which will be immediately thrown away by entity framework to replace it with its own ICollection. Don't automatically initialize property Deleted, if entity framework immediately replaces it with its own value.
You will probably have only one procedure where you will add a Ticket to the database. Use this function to properly initialize the field of any "newly added Ticket"
Don't forget the foreign keys
You defined several relations between your tables (one-to-many, or many-to-many?) but you forgot to define the foreign keys. Because of your use of virtual entity framework can understand that it needs foreign keys and will add them, but in your query you need to write e.Status != null && e.Status.Id == statusId, while obviously you could just use the foreign key e.StatusId == statusId. For this you don't have to join with the Statuses table
Another reason to specify the foreign keys: they are real columns in your tables. If you define that these classes represent your tables, they should be in these classes!
Only select the properties you actually plan to use
One of the slower parts of a database query is the transport of the selected data from the database management system to your local process. Hence it is wise to select only the data you actually plan to use.
Example. There seems to be a one-to-many between a User and a Ticket: every User has zero or more Tickets, every Ticket belongs to exactly one User. Suppose User 4 has 20 Tickets. Every Ticket will have a UserId with a value 4. If you fetch these 20 Tickets without a proper Select you will fetch all properties of the same User 4 once per Ticket, and you will transport the data of this same User 20 times (with all his properties, and maybe all his relations). What a waste of processing power!
Always use Select to query your data and Select only the properties you actually plan to use. Only use Include if you plan to updated the Included data.
var tickets = dbContext.Tickets.Where(ticket => !ticket.Deleted
// improvement: use foreign keys
&& ticket.ProjectId == 0 (or == null, if ProjectId nullable)
&& ticket.StatusId == statusId) // no Join with Statuses needed
.Select(ticket => new
{
...
}

Auto generate GUID in mvc5 that uses EF

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;

Syntax error near AutoIncrement with SQLite Database creation

It's me again, the guy working with SQLite-net. I had my code working when I did not have AutoIncrement on my Primary Keys of the tables. I wanted to AutoIncrement the keys so I reconstructed the Tables like this:
using SQLite;
namespace VehicleTracks.Models
{
public class vehicles
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string VehID { get; set; }
public string VehYear { get; set; }
public string VehMake { get; set; }
public string VehModel { get; set; }
public string VehColor { get; set; }
public string EngineID { get; set; }
public System.DateTime PurchaseDate { get; set; }
public string SellerName { get; set; }
public string SellerStreet { get; set; }
public string SellerCityStateZip { get; set; }
public string VehOptions { get; set; }
public string OdomInitial { get; set; }
public string VehBodyStyle { get; set; }
public float PurchaseCost { get; set; }
public byte[] VehPhoto { get; set; }
public string VehType { get; set; }
public string Sold { get; set; }
}
}
Now when an attempt is made to create the Tables, I get "Syntax Error near AutoIncrement". I tried leaving off AutoIncrement and it does not appear to increment the ID without it.
I'm probably missing something stupid.
Nothing stupid about your code; matches the code samples on https://github.com/praeclarum/sqlite-net alright. But apparently the code samples are wrong, considering this similar problem:
Android table creation Failure (near "autoincrement": syntax error)?
The problem was solved by removing AutoIncrement. Or to quote http://www.sqlite.org/faq.html#q1 :
Short answer: A column declared INTEGER PRIMARY KEY will autoincrement.
(Please double-check whether column ID actually has type INTEGER PRIMARY KEY once the table has been created.)
Longer answer: If you declare a column of a table to be INTEGER PRIMARY KEY, then whenever you insert a NULL into that column of the table, the NULL is automatically converted into an integer which is one greater than the largest value of that column over all other rows in the table, or 1 if the table is empty.
Make sure your INSERT statements do not contain an explicit value (other than NULL) for column ID, otherwise the column will not auto-increment. If that is not possible in SQLite-net (you may need a debugger here), then that may well be a bug. Though it would be surprising that nobody else has ever ran into this.
Maybe you need to make property ID nullable (i.e. use type int?; yes, with the question mark). Mind you, I'm only guessing here; you may need to experiment a bit.
sqlite> CREATE TABLE app (a INTEGER PRIMARY KEY NOT NULL, B VARCHAR);
sqlite> insert into app (b) values ('');
sqlite> insert into app (b) values ('a');
sqlite>
sqlite> insert into app (b) values ('b');
sqlite> insert into app (b) values ('c');
sqlite> insert into app (b) values ('d');
sqlite> select * from app;
1|
2|a
3|b
4|c
5|d
sqlite> exit;
NOTE: IN SQLite AUTOINCREMENT keyword is recommended not to be used. You need to use INTEGER PRIMARY KEY NOT NULL. It will automatically insert the incremented value for this attribute.
I´m new to sqlite-net ( https://github.com/praeclarum/sqlite-net ) and was having issues with an autoincrement PK.
Although I´ve created the table with INTEGER PRIMARY KEY or INTEGER PRIMARY KEY AUTOINCREMENT I got an exception on inserts because the PK was set in 0 in the first row and then I got exception because it tried to insert the same value, so the autoincrement was not working. What I have done is edit the DataAccess.cs and in the table class I´ve replaced the [PrimaryKey] public Int64 id { get; set; } for [PrimaryKey] [AutoIncrement] public Int32 id { get; set; }. I don´t know why it uses bigint (Int64) instead of Int32 as I´ve specified INTEGER in table creation, but now it´s working OK. I can add a new item through LINQ and the autoincrement id (the primary key of the table) increments automatically in each row.

MVC4 / EF5 / Auto Increment

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.