Entity Framework Data Annotations Set StringLength VarChar - entity-framework

I have this setting in my model:
[StringLength(250)]
public string Comment { get; set; }
to set the maximum length to 250 in the database which is great.
However it's set as nvarchar(250) when the database person was expecting varchar(250).
Can somebody please tell me how to set it as a varchar from the model as opposed to an nvarchar?

Use ColumnAttribute to give the datatype
[Column(TypeName = "VARCHAR")]
[StringLength(250)]
public string Comment { get; set; }
Or use fluent API
modelBuilder.Entity<MyEntity>()
.Property(e => e.Comment).HasColumnType("VARCHAR").HasMaxLength(250);

For some reason this older post keeps coming up in my search... so just FYI, using EF6 Core it's combined. The above answer errors out for me.
[Column(TypeName = "VARCHAR(250)")]
public string Comment {get;set;}

Visual Studio 2022 using Net 6 and EF Core 6, database first using the -DataAnnotations parameter creates the following attributes
/* Nullable column */
[StringLength(250)]
[Unicode(false)]
public string? Comment { get; set; }
/* Non-Nullable column */
[StringLength(250)]
[Unicode(false)]
public string Comment { get; set; } = null!;

Related

EF Core 3.1 - How to use an already combined PK for another combined PK?

I´m currently learning to use EF and I have the following relationships:
An Alert has 1 to n occurences.
Each occurence can have 0 to n values (additional information).
public class Alert
{
// PK
public int AlertId { get; set; }
// Attributes
public int CurrentAlertLevel { get; set; }
public DateTime TimeRaised { get; set; }
public DateTime TimeLastRaised { get; set; }
// Some other attributes ommitted...
// Relations
public ICollection<AlertOccurrence> Occurrences { get; set; }
}
public class AlertOccurrence
{
// Relations which are part of the primary key
public int AlertId { get; set; }
// Attributes
public int Ordinal { get; set; }
// some ommited attributes
// Relations
public ICollection<AlertDetailValue> AlertDetailValues { get; set; }
}
public class AlertDetailValue
{
public int AlertDetailValueId { get; set; }
public int Order { get; set; }
public string Value { get; set; }
}
In the DB Context OnModelCreating I´m setting the combined PK for AlertOccurence:
modelBuilder.Entity<AlertOccurrence>().HasKey(ao => new {ao.AlertId, ao.Ordinal});
While it seems that this is working - what I would actually like to archive is the same relationship without the need to have the AlertDetailValueId as PK. The table that EF generates also includes AlertOccurrenceAlertId and AlertOccurrenceOrdinal which seems a waste of space to me.
So what I would like to do is:
Have a combined primary key for AlertDetailValue consisting of AlertDetailValue.Order and the (already combined) PK of AlertOccurence instead of the "artificial" AlertDetailValueId. Is that even possible ?
Part of my problem might be that the PK defined using the fluent api is not part of the data classes. So probably another question to ask would be: Is there a way to use a key defined in fluent api in a entity class ?
Or do I need to include AlertOccurrenceAlertId and AlertOccurrenceOrdinal in my entity class AlertDetailValue - but how do I link them then ?
As I said I´m still trying to get my head around EF so while there might be better ways to do this I´m interested in this special kind of relation / combined(combined) PK even if it might be academic... Any help would be highly appreciated.
Trying to explain what I try to do and what my problem is - and taking a good shower - helped me to ask different questions to google and focus more on the foreign key.
It´s not that I did not try to google it before... I just asked the wrong questions..
So I found this:
Mapping composite foreign key to composite primary key where the foreign key is also a primary key
(While trying the new approch #atiyar also hinted on the missing foreign key...)
My new solution was to change AlertDetailValue to intentionally include the parts that the Occurence PK is build of:
public class AlertDetailValue
{
// relations will be set up in fluent api in OnModelCreating of db context
public int AlertOccurenceAlertId { get; set; }
public int AlertOccurenceOrdinal { get; set; }
public int Order { get; set; }
public string Value { get; set; }
}
And then to tell EF that there is a combined PK and also a combined foreign key:
modelBuilder.Entity<AlertDetailValue>().HasKey(adv => new { adv.AlertOccurenceAlertId, adv.AlertOccurenceOrdinal, adv.Order });
modelBuilder.Entity<AlertOccurrence>().HasMany<AlertDetailValue>(adv => adv.AlertDetailValues).WithOne()
.HasForeignKey(adv => new {adv.AlertOccurenceAlertId, adv.AlertOccurenceOrdinal});

Defining a "one-to-one-to-one" relationship on Firebird 2.5 EF Core

I'm working with EF Core and a third-party Firebird 2.5 database and, for some reason, they decided to, rather than do a simple one-to-one relationship, create a single table with two columns that do that relationship itself, i.e.
STOCK
========
ID_STOCK(int)
more columns (and their datatypes)
STOCK_IDENTIFIER
========
ID_STOCK (int)
ID_IDENTIFIER (int)
STOCK_PRODUCT
========
ID_IDENTIFIER (int)
more columns (and their datatypes)
So, every STOCK has one STOCK_IDENTIFIER, which, in turn, has one STOCK_PRODUCT. Usually, when I'm creating my own DB in MySQL, I just set foreign keys with data annotations (I'm not fluent in Fluent API, pun intended) and let the migration do its job. However, in this case I can't change the DB's schema (on the account of it being third-party), so I need to use the existing structure.
Right now I have the following:
public class STOCK
{
[Key]
public int ID_STOCK { get; set; }
[MaxLength(50)]
public string DESCRIPTION { get; set; }
[Column(TypeName = "decimal(18, 4)")]
public decimal SELL_PRICE { get; set; }
public STOCK_IDENTIFIER STOCK_IDENTIFIER{ get; set; }
}
public class STOCK_IDENTIFIER
{
[ForeignKey("ID_STOCK")]
public STOCK ID_STOCK { get; set; }
public STOCK_PRODUCT ID_PRODUCT { get; set; }
}
public class STOCK_PRODUCT
{
[ForeignKey("ID_PRODUCT")]
public STOCK_IDENTIFIER ID_IDENTIFIER{ get; set; }
[MaxLength(18)]
public string GTIN{ get; set; }
[MaxLength(18)]
public string SKU{ get; set; }
[Column(TypeName = "decimal(18, 4)")]
public decimal INSTOCK_AMNT { get; set; }
}
I read at The property X is of type Y which is not supported by current database provider that Fluent API could fix that, however, that article works flawlessly for one-to-one. As soon as I try to implement Fluent on a cascading relationship like this one, I get
modelBuilder.Entity<STOCK_IDENTIFIER>()
.HasOne<STOCK_PRODUCT>(p => p.ID_IDENTIFIER)
.WithOne();
modelBuilder.Entity<STOCK>()
.HasOne<STOCK_IDENTIFIER>(p => p.IDENTIFICADOR)
.WithOne();
The property or navigation 'ID_IDENTIFIER' cannot be added to the entity
type 'STOCK_PRODUCT' because a property or navigation with the
same name already exists on entity type 'STOCK_PRODUCT'.
Any hints on what I've been doing wrong?

Entity Framework 6: map complex type to multiple columns

I have a problem with Entity Framework (6, not Core). I already tried several things and googled around but I can't figure it out so I'm asking here.
Thats my db-scheme:
CREATE TABLE MyItem
(
[Id] int IDENTITY(1,1) NOT NULL,
[Name] varchar(100) NOT NULL,
[Start] date NOT NULL,
[End] date NOT NULL
)
And these are my classes:
public class MyItem
{
public int Id { get; set; }
public string Name { get; set; }
public MyTimespan IsValidTimespan { get; set; }
}
public class MyTimespan
{
public DateTime Start { get; set; }
public DateTime End { get; set; }
}
I want to map
the value from "MyItem.IsValidTimespan.Start" to the "Start"-column
the value from "MyItem.IsValidTimespan.Ende" to the "Ende"-column
I already tried different things with Attributes on the MyTimespan-class ("ComplexType" and "Column" Attributes) and also some hacks with the modelBuilder, nothing worked.
How can I get this to work?
Thank you and best regards,
Alex
Ok I got it. The code I posted above is not 100% correct: the properties of MyTimespan did not had setters. The following changes in "MyTimespan" did it:
adding the annotations mentioned in my question
adding private setters to the properties
adding a private default constructor

EF creating an unwanted field in database

I've hit a snag while building a .net mvc site. I have 2 related objects and am struggling with properly linking them. Specifically:
public class Address
{
public int AddressId { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string State { get; set; }
public string PostCode { get; set; }
[ForeignKey("AddressCategory")] // <-- EF adds field to below object's table
public int AddressCategoryId { get; set; }
public virtual AddressCategory AddressCategory { get; set; }
}
public class AddressCategory
{
public int AddressCategoryId { get; set; }
public string Description { get; set; }
}
Adding the [ForeignKey] data annotation to the Address object results in EF adding an Address_AddressId column to the AddressCategory table, which I don't want (or need) to happen.
I've tried to omit the ForeignKey attribute, but then I run into other errors because .net can't link the tables (e.g. Unknown column 'Extent1.AddressId' in 'field list'). Additionally, I wouldn't be able to use:
var addresses = db.Addresses.Include(l => l.AddressCategory);
Is there any way to link the 2 tables without EF adding an additional column to the AddressCategory table?
Thank you to #cloudikka for responding. After much trial-and-error I seem to have gotten it to work simply by omitting any ForeignKey reference from either object. I let EF rebuild the database and perform all scaffolding (CRUD forms) and they have been created perfectly.
My take-away is that foreign key attributes should be used for parent-child relationships, but not for look-up tables. I clearly have much to learn about asp.net mvc!

EntityFramework 6.1 Add Method

I have a very simple problem. Always use like this, but now not working, why i dont know.
I'm working on MVC 4 and Entity Framework 6.1.
I have sql table like picture below which name is Kategori,
Translation: KategoriID -> CategoryID, KategoriIsmi -> Category, UstKategoriId -> ParentCategoryID
KategoriID column has also, Primary Key and Identity Specification YES (Identity Increment 1, Seed 1)
And this is my Kategori Model class
public class Kategori
{
[Key]
public byte? KategoriID { get; set; }
[Required(ErrorMessage = "Please insert category name")]
public string KategoriIsmi { get; set; }
public byte? UstKategoriID { get; set; }
}
And my save code with EntityFramework
public void AddNewItem(Kategori item)
{
using (EmlakCMSContext _ent = new EmlakCMSContext())
{
_ent.Kategori.Add(item);
_ent.SaveChanges();
}
}
When I run this code
Income data (for save in db)
I have a error. And I write code, watch the error in IntelliTrace.
Error Translate: KategoriID alanı gereklidir -> CategoryID field is required.
But KategoriID field have set auto increment true.
How can i solve this problem? Thanks.
It's hard to tell as the error message is not in English. However, your primary key should not use a nullable data type. Change this:
public byte? KategoriID { get; set; }
To this:
public byte KategoriID { get; set; }
You may also need to tell entity framework that the column is an IDENTITY column:
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public byte KategoriID { get; set; }