Consider the following database tables:
CREATE TABLE [dbo].[Step]
(
[StepId] INT NOT NULL PRIMARY KEY IDENTITY,
[OrderIndex] INT NOT NULL
)
CREATE TABLE [dbo].[StepInput]
(
[StepInputId] INT NOT NULL PRIMARY KEY IDENTITY,
[StepId] INT NOT NULL,
[OrderIndex] INT NOT NULL,
CONSTRAINT [FK_StepInput_Step] FOREIGN KEY ([StepId]) REFERENCES [Step]([StepId]) ON DELETE CASCADE,
)
With the following POCOs:
public class Step
{
public virtual int StepId { get; set; }
public virtual ICollection<StepInput> StepInputs { get; set; }
}
public class StepInput
{
public int StepInputId { get; set; }
public int StepId { get; set; }
public virtual int OrderIndex { get; set; }
}
I would like for StepInputs to be ordered by OrderIndex. Is there any way to setup the navigation property so that it is sorted automatically by EF, so that the user of Step does not have to call StepInputs.OrderBy every time?
I am using the database-first model.
Edit: I did realize that I could just add an OrderedInputs property to Step, which returns StepInputs.OrderBy(...), which solved the immediate problem, though I'm not sure about the performance implications. I am still curious as to whether there is a way to set this up in EF without having to use a custom property.
No way...! I think you have two tricks:
1) Create a static dbcontext, and for the first time, load the data you need into memory using .load() and perform your ordering, and then just use in-memory data in the Local property of your dbctx.<DbSet>s - an ugly way and most probably doesn't satisfy you...
2) Create a stored procedure to retrieve your data and perform ordering in database, and map that sp to an entity in your model.
Related
I have an issue that I can't seem to get around. I'm working with renewing an application based on an existing MySQL database. I'm using EF Core 6.0.1 and Pomelo.EntityFrameworkCore.MySql 6.0.0.
I can easily retrieve data from tables so I know the setup is working. However - when I try to map an entity to a table containing a nullable value in MySql, EF Core throws an error:
System.InvalidCastException: Unable to cast object of type 'System.DBNull' to type 'System.String'.
A short example could be this class:
public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Email { get; set; };
}
Mapped to a table in MySQL:
CREATE TABLE `Users` (
`Id` INT(11) NOT NULL,
`Username` VARCHAR(50) NULL DEFAULT NULL,
`Email` VARCHAR(200) NULL DEFAULT NULL,
PRIMARY KEY (`Id`) USING BTREE
;
I have the following mapping in place:
public void Configure(EntityTypeBuilder<User> builder)
{
builder.ToTable("Users");
builder.HasKey(o => o.Id);
builder.Property(t => t.Username).HasColumnType("varchar").HasMaxLength(50);
builder.Property(t => t.Email).HasColumnType("varchar");
}
In the current example the Username and Email fields can contain null values in the DB (and they do).
If I remove Username and Password from my class, then everything works. But whenever I have a nullable type I try to map, I get the DBnull exception.
I'm very new to using EF with MySQL - so I figure there might be something I'm missing? :)
As per the comments from #GertArnold and #SvyatoslavDanyliv below, I fixed my issue by doing the following:
Ensuring that my csproj file had <Nullable>enable</Nullable>
Set my Username and Email properties to nullable reference types by using string? instead of just string
Solved everything right away.
Thanks guys.
I've started a new .net core 2 project and I'm trying to import a MySQL database to entity framework.
I use this command to scaffold the DB:
Scaffold-DbContext "server=localhost;port=3306;user id=user;password=pass;database=MyDB;" "Pomelo.EntityFrameworkCore.MySql"
The process is successful, but I get this type of warning for each table that contains date columns:
Could not find type mapping for column
'my_table.DATE_ADDED' with data type 'date'. Skipping
column.
This is the table:
ACCOUNT_ID int(10) UN PK
VIDEO_ID int(10) UN PK
DATE_ADDED date
The model being created is this:
public partial class MyTable
{
public int AccountId { get; set; }
public int VideoId { get; set; }
public Accounts Account { get; set; }
public Videos Video { get; set; }
}
My question is, is there any way to do the scaffolding process that will include date fields? if not, is there any way to fix the model so it can use the date data?
I have inherited a sql server database and an ASP.Net MVC 4 web application which is using Entity Framework 5.0 Code First with Auto Migrations . However, it appears the previous developer forgot to add a Primary Key to one of the tables. I am now trying to do this using Auto Migrations, however, it is not working, no errors either, just seems to be ignoring the command.
The table is like this
public int CourseDateHistoryID { get; set; }
public int CourseDateID { get; set; }
public int Event { get; set; }
//public string testProp{ get; set; }
And my mapping is like this to try and create the primary key on CourseDateHistoryID
this.HasKey(t => t.CourseDateHistoryID);
this.Property(t => t.CourseDateHistoryID)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.Identity);
I thought maybe the connection string was wrong or something, so I tried to add a dumby string property called testProp using auto migrations, but this worked fine.
Would anyone have any ideas as to why I cannot set CourseDateHistoryID as the PK using auto migrations?
Thanks for any help.
You can try manually updating the database using Update-Database -verbose command. It should show you the migration it's applying as well as the errors it encounters.
Or why not add another migration using the Add-Migration command and manually add primary key there, for example:
public partial class AddPrimaryKey : DbMigration
{
public override void Up()
{
AddPrimaryKey(table: "dto.table", column: "CourseDateHistoryID", name: "PK_CourseDateHistoryID");
}
public override void Down()
{
DropPrimaryKey(table: "dto.table", name: "PK_CourseDateHistoryID");
}
}
Hope this helps.
I am learning about the Entity Framework and POCOs and while I like a lot of the concepts, I think I am not quite getting it. Here's an example:
I have a schema like the following:
create table Customer
{
Id int,
Name varchar(32),
Value1 varchar(32),
Value2 varchar(32),
Value3 varchar(32)
...
Value50 varchar(32)
}
-- ColumnName will map to "Value1", "Value2", etc
create table ColumnMapping
{
ColumnName varchar(32),
DisplayName varchar(32)
}
The object which represents this data looks like:
class Customer
{
public Id { get; set; }
public Name { get; set;}
public Dictionary<string, string> CustomData { get; set; }
}
That is, I'd like to map the Value1 to Value50 to a Dictionary (where the Key of the dictionary is determined by the ColumnMapping table).
I am wondering what the best approach to this.
I'd like the Customer to be a POCO, but in order to do that, it would need to know about Value1..Value50 so that it would be able to convert those columns into a dictionary. But given that a POCO should be persistent ignorant, I am questioning if that is the right approach.
I guess, in general, I am struggling with what the POCO really is - is it the object which is used by the business layer, or does there need to be a mapping between the POCO and a "business object" and the "business object" is what should be used by the business layer.
Any advice on how to deal with this type of scenario will be appreciated.
Edit
As I didn't receive an answer to the question I was trying to ask, I'll go ahead and indicate what I decided (in case anyone has this similar issue). While the POCO is persistent ignorant in that it doesn't need to know about how it gets persisted, it's not entirely persistent ignorant. That is, it has to be tied to the persistence layer in some manner.
In my example, while I don't want the business layer to know about Value1, Value2, Value3, etc, someone needs to know about it in order to convert those values to a dictionary. I believe that the right place to put that logic is the POCO and hence, I believe the POCO should have properties for the Value1, Value2, Value3, etc, columns.
Thanks,
Eric
In ORM world, this is typical approach
class Customer
{
public int Id { get; set; }
public string Name {get; set; }
public virtual ICollection<CustomDatum> CustomData { get; set; }
}
class CustomDatum
{
public int Id { get; set; } // PK
public string ColomnName { get; set; }
public string DisplayName { get; set; }
}
I have got this weird error Cannot add an entity with a key that is already in use
But what is quite irritable about that error is that user gets no detais - Who? What? What table? What record is the culprit of this error?
It would be desperately complicated to determine it, in case you do many operations on LINQ objects before .Submit()
Is there any way to determine what certainly caused this error?
This error typically happens when you are creating a new record in a MetaTable with a foreign key relationship and the foreign key record already exists.
For example, let's say you have an Contact table and an Address table, and each Contact can hold multiple Addresses. The error occurs when you create a new Contact record and try to manually associate an existing Address record to that new Contact.
Assuming that the passed Address ID represents an existing Address record, this doesn't work:
public class Contact
{
public int Contact_ID { get; set; }
public string Name { get; set; }
public Address ContactAddress { get; set; }
public string Phone { get; set; }
}
public class Address
{
public int Address_ID { get; set; }
public string Street { get; set; }
public string CityState { get; set; }
public string ZIP { get; set; }
}
public void CreateNewContact(int addressID)
{
Contact contact = new Contact();
contact.Name = "Joe Blough";
contact.ContactAddress.Address_ID = addressID;
contact.Phone = "(555) 123-4567";
DataContact.SubmitChanges();
}
Historically, SQL developers are trained to just pass the ID value in order for the magic to happen. With LINQ-to-SQL, because the database activity is abstracted, we have to pass the whole object so that the LINQ engine can properly reflect the necessary changes in the ChangeSet. In the above example, the LINQ engine assumes that you are asking to create a new Address record, because it didn't have one to work with when the SubmitChanges was made and it has to respect the contract established by the foreign key relationship. It creates a blank Address record with the passed ID value. The error occurs because that ID value already exists in the data table and the ChangeSet has not flagged the Address delta as an Update.
The fix is to pass in the entire record, not just the ID value:
contact.ContactAddress = DataContext.Addresses.Where(a => a.Address_ID == addressID).Single();
Now, the LINQ engine can properly flag the incoming Address record as an existing one and not try to recreate it.
May be the column you trying to Attach(), Remove(), Add() or DeleteOnSubmit(), is a primary key and you are trying to add or attach the same value again.
Also you might be accessing a primary key or foreign key value column in a different method and it's not closed yet when you trying to call the above methods.
Above to these methods Attach(), Remove(), Add() or DeleteOnSubmit(), try to create a new instance of your datacontext again and run.
It sounds like you are doing an Table.Attach() and the entity you are attaching has a key value that L2S is already tracking. This has got nothing to do with a duplicate key in your physical database.
As explained on one of the answers above, this error is more likely due to trying to insert a record into the table with a repeated value on primary ID key field. You could solve the problem by selecting/creating a different primary key.