I am currently working on my first project based on Entity Framework 6 with VS2012 using a SQL Server Compact database (model first).
Currently I am wondering how to declare an Entity column to be indexed (not unique values) in the database without being the primary key.
Thank you for any hints.
You can't specify an index through the designer. This can only be specified in the database, if you do Database-First, or through the model, if you do Code First. My preference is Database First, but your mileage may vary.
You can use the Index attribute to create Index on a particular column in the database as shown below:
class Student
{
public Student()
{
}
public int Student_ID { get; set; }
public string StudentName { get; set; }
[Index]
public int RegistrationNumber { get; set; }
}
You can also specify it to be clustered with IsClustered = true and a unique index by specifying IsUnique=true.
[Index( "INDEX_REGNUM", IsClustered=true, IsUnique=true )]
public int RegistrationNumber { get; set; }
See https://msdn.microsoft.com/en-us/data/jj591583.aspx for details like unique indexes and multicolumn indexes.
Related
This is my diagram in my database:
but when I use Entity Framework it was like that:
It hasn't table name ListSuiteQuestion but It has 2 new property in class Question and Suite:
enter image description here
Table ListSuiteQuestion is automatically created by sql because in sql we don't have something called many to many relationship (m:n) and sql creates another table to implement m:n relationship with keys containing the primary key of two relationship tables is also the name of the combination of the names of the two relation tables.
Within your entity framework by accessing each table through another table you have access to that table so there is no need to define it by entity framework. However, if you intend to customize or add a field to a third table you can manually build it into the code and then display it entity framework, though you don't need to.
if you want create it manually in code do like this :
public class Suite
{
//another property
public int IdSuite { get; set; }
public virtual ICollection<SuitQuestions> Questions { get; set; }
}
public class Question
{
//another property
public int IdQuestion { get; set; }
public virtual ICollection<SuitQuestions> Suites { get; set; }
}
public class SuiteQuestions
{
public Suite Suite { get; set; }
public int IdSuite { get; set; }
public Question Question { get; set; }
public int IdQuestion { get; set; }
//add custome property if you need
}
and config it.
It's correct. A question has a list of suites and a suite has a list of questions.
If you do:
var suite = context.Suites.Find(5);
var question = context.Questions.Find(30);
suite.Questions.Add(question);
// And update this suite object here;
You will see a new record in ListSuiteQuestion Tables with IdSuite = 5 and IdQuestion = 30. The class ListSuiteQuestion doesn't need to be created.
However, if you really want to create the class you have to add Id to the Table ListSuiteQuestion as primary key.
I'm a beginner with EF (6.2) and I'm trying to generate a database using the code first approach.
Some of my entities have a string property which should be unique, like the name of a user or the title of an article.
In order to ensure unicity, I've added an index which specifies that the column should be unique :
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Blog.Models
{
public class User
{
[Key, Index, Required]
public int Id { get; set; }
[Index(IsUnique = true), Required]
public string Name { get; set; }
[Required]
public string Password { get; set; }
public ICollection<Comment> Comments { get; set; }
}
}
However it complains because I'm trying to add an index on a string type column, while it accepts using an index on an integer column, such as the row ID.
I could use the Key attribute, but I'm already using it to define a primary key and I don't want EF to beleive that I want the name to be a component of a composite primary key nor to consider it as the actual primary key.
So my question is : Why can't I add an index on a column of string type and how can I ensure the unicity (uniqueness ?) of a given column ? Thank you.
As written in the Tutorial from MSDN, Indexes are possible on strings as they state in the following example code
public class User
{
public int UserId { get; set; }
[Index(IsUnique = true)]
[StringLength(200)]
public string Username { get; set; }
public string DisplayName { get; set; }
}
but when it comes to Multiple-Column Indexes, they mention you need to write the order.
Probably there's a conflict arising because you use Index without any name on Id, and also an Index without any name on Name. Try defining a name for the Index of the Name. I am not sure if this works, but it's worth a try.
More info can be found here at the MSDN website.
I am trying to create a generic Insert<T> for our objects. I am new to OrmLite so I am still reading up on it. The objects that are used do not use an Id property they have a more detailed name.
As an example this a basic POCO:
public class Customer
{
public int CustomerId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
...etc.
}
So the primary key is CustomerId and through some more reading I found that OrmLite likes to use the property Id for the primary keys. As we have a convention not to use just the name Id for the FK I cannot switch. However reading further it seemed like I could decorate the property with an attribute or two and get it to work.
This is what I am working with:
public class Customer
{
[AutoIncrement]
[Alias("CustomerId")]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
...
}
I get a SqlException stating the following:
Additional information: Cannot insert the value NULL into column 'CustomerId',
table 'XXX.dbo.Customer'; column does not allow nulls. INSERT fails
I did some more reading and thought I could fix the issue by inheriting from an interface.
public class Customer : IHasId<int>
{
[AutoIncrement]
[Alias("CustomerId")]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
...
}
I have played with using the PrimaryKey attribute and I still get the same result.
Has anyone had an issue like this? If you did how did you solve it? I am having a hard time finding some more information on the matter.
I can get rid of the attributes and name the property back to CustomerId so it matches the db table and it will insert into the table but it will always put in 0 as the key, which makes sense just because it is the default value for the int but does not help me when it has to be an autoincrementing primary key. As a side note I am using ServiceStack.OrmLite.SqlServer.3.9.71 and SQL Server 2008
UPDATE 1
So I went through the documentation again today for 3.9 version of ServiceStack.OrmLite and read through their description on what I should do when I don't have POCOs with an 'Id' property for the Primary Key. It is as follows:
... by convention OrmLite expects it to be Id although you can use [Alais("DbFieldName")] attribute to map it to a column with a different name or use the [PrimaryKey] attribute to tell OrmLite to use a different property for the primary key.
I used both of the examples and it does in fact insert my data to the SQLDatabase. However, it is still inserting 0 for the CustomerId primary key.
If I use the AutoIncrement attribute it throws a SqlException:
An exception of type 'System.Data.SqlClient.SqlException' occured in System.Data.dll but was not handled by user code. Additional Information: Cannot insert the value NULL into column 'CustomerId', table 'dbo.Customer'; column does not allow nulls. INSERT fails.
Has anyone run into this issue? I keep running into roadblocks.
i experimented the same issue. Your following code was already good.
public class Customer
{
[AutoIncrement]
[Alias("CustomerId")]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
...
}
The problem don't come from ORMLITE but from your database. Indeed, the column "CustomerId" which is i think the primary key for your table have his property "Identity" set to "False". You must set it to "True" or "Yes" and also set "Identity Increment" and "Identity Seed" to 1.
In v4.0.40, servicestack retrieves the primary key column by naming convention ("column_name" == OrmLiteConfig.IdField) as shown by the following code from OrmLiteConfigExtensions.cs:
internal static bool CheckForIdField(IEnumerable<PropertyInfo> objProperties)
{
// Not using Linq.Where() and manually iterating through objProperties just to avoid dependencies on System.Xml??
foreach (var objProperty in objProperties)
{
if (objProperty.Name != OrmLiteConfig.IdField) continue;
return true;
}
return false;
}
Therefore, using [AutoIncrement] with [Alias] should not work.
How can I update all the records with Keyword_Id = 1 to Keyword_Id = 2?
public class KeywordAddressCategory
{
[Key]
[Column("Keyword_Id", Order = 0)]
public int Keyword_Id { get; set; }
[Key]
[Column("Address_Id", Order = 1)]
public int Address_Id { get; set; }
[Key]
[Column("Category_Id", Order = 2)]
public int Category_Id { get; set; }
}
I get an exception saying that I can't update a key of the entity.
Thanks
This is probably because those three properties are all part of the composite primary key, and as Entity Framework elegantly points out: you can't change the primary key value.
If this is at all an option, I would consider NOT using a composite primary key but a separate primary key for this class. You'll find it makes using foreign keys a lot simpler.
So, something like this:
[Key]
public int KeywordAddressCategoryId { get; set; }
public int Keyword_Id { get; set; }
public int Address_Id { get; set; }
public int Category_Id { get; set; }
With this system identity constraints, foreign keys, passing around id values as route values or as hidden fields in forms, ... all become much easier. And for your question: you can then easily change the Keyword_Id value because you CAN change a foreign key value easily.
I know this doesn't really answer your question, because I haven't told you how you can actually change the value, but I wanted to post this answer anyway so maybe you could reconsider your database structure.
Edit: see this question on how you can achieve what you want, if you really can't or aren't willing to change your DB structure: Update part of primary key Entity Framework 4.0
I am using Entity Framework Code First in my ASP.NET MVC application. One of my classes has several columns that are added together. I am storing these columns as computed columns in the tables by running an alter table script in the database initializer. Let's say the class looks like:
public class Bond
{
public decimal ParAmountOfIssuance { get; set; }
public decimal AccruedInterest { get; set; }
public decimal Premium { get; set; }
public decimal OriginalIssueDiscount { get; set; }
}
The alter script is something like:
alter table Bonds
add TotalSources as (ParAmountOfIssuance + AccruedInterest + Premium - OriginalIssueDiscount)
I want the Total Sources column to be available for viewing in the web app. What's the best way to accomplish this? The [DatabaseGenerated(DatabaseGeneratedOption.Computed)] attribute doesn't work because EF Code First creates the table from the class before the alter script is ran.
Any suggestions are welcome.
I have a somewhat of an workaround.
You can only use calculated field on a existing database.
If you add your property to CF object as:
[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
public decimal TotalSources { get; set; }
and if you add a line in your script that will delete information about generation of that database:
DELETE FROM [dbo].[EdmMetadata]
CF will assume it is existing database and it will work, I have just tried.
UPDATE I forgot, if you add property to your Bond entity like this, then in your script you need to alter it to make it calculated, not add it :)
You can even manually "synchronize" database and model - at point where you have everything working without this field, add it in model as computed, and in table as calculated. When you delete hash from edm metadata table CF will work without trying to regenerate model with database.
This is definitely not supported - defining Computed option on custom property will throw exception. Code first = logic in code. If you need custom computed properties use database first. The only database logic supported by code first is identity column and timestamp.
The problem is that you need the column to be marked as computed but creating database will not allow that. If the column is not marked as computed it will be updatable = EF will generate update statements trying to update this column which will fail in the database.
I'm doing computed columns in CF (WinForms) like that (I don't know if it's the best):
This is one Entity:
public class Result
{
public int ResultId { get; set; }
public int StudentId { get; set; }
public Student Student { get; set; }
public float Arabic { get; set; }
public float English { get; set; }
public float Math { get; set; }
public float Science { get; set; }
public float Total { get; set; }
}
This is Form2:
private void Form2_Load(object sender, EventArgs e)
{
Model1 model = new Model1();//Model1 : DbContext
model.Database.CreateIfNotExists();
model.Database.ExecuteSqlCommand("alter table Results drop column Total; alter table Results add Total AS (Arabic + English + Math + Science)");
var r1 = (from s in model.Students
join r in model.Results
on s.StudentId equals r.StudentId
select new { s.StudentName, r.Arabic, r.English, r.Science, r.Math, r.Total }).ToList();
dataGridView1.DataSource = r1;
}