I am playing around with EF 5 and code first. So far I really like it, but I have noticed it defaults string columns to nvarchar. If I want to use varchar, then I have to explicitly tell it to.
I can force it to use varchar instead of nvarchar for strings as follows:
public class Member
{
public int id { get; set; }
[MaxLength(255), Required, Column(TypeName = "varchar")]
public string firstName { get; set; }
[MaxLength(255), Required, Column(TypeName = "varchar")]
public string surname { get; set; }
}
I would typically use varchar instead of nvarchar in almost all cases though, so I would much prefer to have string columns globally mapped to varchar, and to be able to set nvarchar on a per-column basis as above if I need to.
Does anyone know a way to do this? I am trying to omit the need for typing [Column(TypeName = "varchar")] for every string column in my model.
on EF 6 you can use this to map every string property to use varchar instead nvarchar
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Properties()
.Where(x =>
x.PropertyType.FullName.Equals("System.String") &&
!x.GetCustomAttributes(false).OfType<ColumnAttribute>().Where(q => q.TypeName != null && q.TypeName.Equals("varchar", StringComparison.InvariantCultureIgnoreCase)).Any())
.Configure(c =>
c.HasColumnType("varchar"));
}
Or
modelBuilder.Properties<string>().Configure(c => c.IsUnicode(false));
You must write it as:
[Column(TypeName = "VARCHAR")]
public string firstName { get; set; }
For many info please look at this link
Related
Problem: I'm calling a stored procedure through EF Core. When I run the stored procedure directly (via 'debug procedure'), it runs quickly, but it runs VERY slowly when called by EF's FromSqlRaw. So the problem appears to be when converting the returned data-table to a list of objects.
Setup:
Simple application with a list of blog posts. The stored procedure gets a hierarchical list of posts and associated users from a TPH table of posts, plus a table of users.
// Code is simplified, actually 8 parameters
SqlParameter depth_p = new SqlParameter("#depth", depth);
SqlParameter authorizedUserID_p = new SqlParameter("#authorizedUserID", authorizedUser.ID);
IQueryable<PostUser> query = postContext.PostUsers
.FromSqlRaw("Post.USP_ReadDebate #depth, #authorizedUserID",
parameters: new[] { depth_p, authorizedUserID_p });
List<PostUser> postUsers = query.ToList(); // This hangs.
26 columns are returned and converted by EF into the PostUser class.
PostUser holds 26 "ordinary" properties. No navigation properties, custom classes or any getters or setters that do any work.
public class PostUser
{
// Post fields
public Int32? ID { get; set; } // Primary Key
public String Text { get; set; }
public Guid OwnerID { get; set; }
public int? ParentID { get; set; } // nullable
public bool IsDisabled { get; set; }
public DateTime TimeCreated { get; set; }
public bool User_IsBanned { get; set; } = false;
// some others...
public PostUser() { }
}
Note: the stored procedure is very complex. It calls another stored procedure which fills a #spid table, then inserts the contents of that #SPID table into a table variable and returns that.
But again when debugged directly it returns quickly, so I think the problem is when EF Core is converting the returned data to the PostUser object.
Bottom Line: is there any way to get visibility into what EF Core is doing on the conversion to PostUser to find the problem?
Thank you!
For a table defined
public class Tbl
{
[PrimaryKey]
public int Id { get; set; }
public string Col2 { get; set; }
public string Gen { get; set; }
}
Where Gen is a Sqlite stored generated always column
on _conn.Insert(instanceOfTbl)
I get 'cannot UPDATE generated column'.
Fair enough, but other than directly executing an equivalent sql statement which ignores Gen is there a way of flagging Gen as generated (or other method) to allow the insert/update? I don't think the [Ignore] column attribute is appropriate as Gen needs to be accessible for reading. Removing the Set accessor does prevent the behaviour but results in the property always being null when read.
I'm using VS, Xamarin, Nuget sqlite-net-pcl 1.7.335 targeting Android, if relevant.
I've decided to adopt this approach for now. Credit to Jason for pointing me towards it.
Split Tbl into base class Tbl and derived class TblEx. Move the generated column property to TblEx. Hardwire TblEx to map to Sqlite table Tbl. Provide TblEx method to retrieve only properties from base class Tbl.
public class Tbl
{
[PrimaryKey]
public int Id { get; set; }
public string Col2 { get; set; }
}
[SQLite.Table("Tbl")]
public class TblEx : Tbl
{
public string Gen { get; set; }
public Tbl GetTbl() {Tbl t = new Tbl(); t.Id = Id; t.Col2 = Col2; return t;}
}
Update record with primary key id
TblEx tEx = _conn.Table<TblEx>().First(t => t.Id == id);
// Generated field is available as class is TblEx
tEx.Col2 = tEx.Gen + "something";
//Update now works as only base class Tbl without reference to generated column is passed
_conn.Update(tEx.GetTbl());
An alternative way of retrieving the base class uses JSON serialize/deserialize which has the advantage of not having to explicitly assign property values but may come with a performance cost or type compatibility limitations (I'm not sure that the latter's true as I don't know much about JSON).
using System.Text.Json;
[SQLite.Table("Tbl")]
public class TblEx : Tbl
{
public string Gen { get; set; }
public Tbl GetTbl()
{return JsonSerializer.Deserialize<Tbl>(JsonSerializer.Serialize(this));}
}
I'm using EF Core which I believe is also known as EF 7? Anyways, I have a stored procedure that returns custom results that will not identify with any specific table. How am I supposed to access those results and how should I call the sql command?
Normally we have to use .FromSql but that is only available on entities, eg. _context.User.FromSql(). I don't have an entity for it.
So I tried building a dbset/entity for the results, but again, there is no associated table, and there is also no "Key". How am I supposed to parse the data then of the custom results?
You can create a fake entity for the result of your stored procedure. You can set any property as the Key, even if in the results of the stored procedure the key values are not unique.
For example if you have a table like the following :
CREATE TABLE [dbo].[banana_hoard]
(
[id] INT NOT NULL PRIMARY KEY IDENTITY (1,1),
[owner] NVARCHAR(64) NOT NULL,
[bananas] BIGINT NOT NULL
)
You can have a query that does not return the row id like this :
public class Program
{
public static void Main(string[] args)
{
using (var db = new MonkeyDbContext())
{
var sp_results = db.search.FromSql(#"execute <YOUR_STORED_PROC>");
str_result = String.Join("\n", sp_results.Select(a => JsonConvert.SerializeObject(a) ));
Console.WriteLine("stored proc result :\n" + str_result);
}
}
}
public class MonkeyDbContext : DbContext
{
public DbSet<StoredProcRow> search { get; set; }
protected override void OnConfiguring (DbContextOptionsBuilder builder)
{
builder.UseSqlServer(#"Server=(localdb)\monkey_db;Database=monkey_db;Trusted_Connection=True;");
}
}
public class StoredProcRow
{
[Key]
public string Owner { get; set; }
public long Bananas { get; set; }
}
I am using EF 6 and trying to map a many to many relationship. So far I have:
public partial class ObjectiveDetail
{
public ObjectiveDetail()
{
this.SubTopics = new List<SubTopic>();
}
public int ObjectiveDetailId { get; set; }
public string Text { get; set; }
public virtual ICollection<SubTopic> SubTopics { get; set; }
}
public partial class SubTopic
{
public SubTopic()
{
this.ObjectiveDetails = new List<ObjectiveDetail>();
}
public int SubTopicId { get; set; }
public int Number { get; set; }
public string Name { get; set; }
public virtual ICollection<ObjectiveDetail> ObjectiveDetails { get; set; }
}
Our DBA is going to write the code for the many to many table. Should this be as follows
with a table name of ObjectiveDetailSubTopic or something completely different ?
CREATE TABLE [dbo].[ObjectiveDetailSubTopic] (
[ObjectiveDetailId] INT NOT NULL,
[SubTopicId] INT NOT NULL
);
Can someone tell me if this is the correct way to create the table. Also do I have to
add some code to map the ObjectiveDetail and SubTopic classes to the new join class so
EF will know what to do?
Our DBA is going to write the code for the many to many table. Should
this be as follows with a table name of ObjectiveDetailSubTopic or
something completely different ?
As long as you follow the SQL Database table naming conventions, the table name can be anything. I usually name the join table like yours, by connecting the two table names.
To create the join table using sql, see below:
CREATE TABLE [dbo].[ObjectiveDetailSubTopic](
ObjectiveDetailSubTopicId int identity primary key,
ObjectiveDetailId INT NOT NULL,
SubTopicId INT NOT NULL,
foreign key(ObjectiveDetailId) references ObjectiveDetail(ObjectiveDetailId ),
foreign key(SubTopicId) references SubTopic(SubTopicId )
);
But you don't need to create the join table by your own, Entity Framework will create it for you. You just need to mapping the relationship with the Fluent API in your DbContext class like below:
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
modelBuilder.Entity<ObjectiveDetail>().
HasMany(c => c.SubTopics).
WithMany(p => p.ObjectiveDetails).
Map(m =>
{
m.MapLeftKey("ObjectiveDetailId ");
m.MapRightKey("SubTopicId ");
m.ToTable("ObjectiveDetailSubTopic");
});
}
What’s Automapper for?
How will it help me with my domain and controller layers (asp.net mvc)?
Maybe an example will help here...
Let's say you have a nicely-normalized database schema like this:
Orders (OrderID, CustomerID, OrderDate)
Customers (CustomerID, Name)
OrderDetails (OrderDetID, OrderID, ProductID, Qty)
Products (ProductID, ProductName, UnitPrice)
And let's say you're using a nice O/R mapper that hands you back a well-organized domain model:
OrderDetail
+--ID
+--Order
|--+--Date
|--+--Customer
|-----+--ID
|-----+--Name
+--Product
|--+--ID
|--+--Name
|--+--UnitPrice
+--Qty
Now you're given a requirement to display everything that's been ordered in the last month. You want to bind this to a flat grid, so you dutifully write a flat class to bind:
public class OrderDetailDto
{
public int ID { get; set; }
public DateTime OrderDate { get; set; }
public int OrderCustomerID { get; set; }
public string OrderCustomerName { get; set; }
public int ProductID { get; set; }
public string ProductName { get; set; }
public Decimal ProductUnitPrice { get; set; }
public int Qty { get; set; }
public Decimal TotalPrice
{
get { return ProductUnitPrice * Qty; }
}
}
That was pretty painless so far, but what now? How do we turn a bunch of OrderDetails into a bunch of OrderDetailDtos for data binding?
You might put a constructor on OrderDto that takes an OrderDetail, and write a big mess of mapping code. Or you might have a static conversion class somewhere. Or, you could use AutoMapper, and write this instead:
Mapper.CreateMap<OrderDetail, OrderDetailDto>();
OrderDetailDto[] items =
Mapper.Map<OrderDetail[], OrderDetailDto[]>(orderDetails);
GridView1.DataSource = items;
There. We've just taken what would otherwise have been a disgusting mess of pointless mapping code and reduced it into three lines (really just two for the actual mapping).
Does that help explain the purpose?
If you have an object of one type and you want to populate the properties of an object of another type using properties from the first type, you have two choices:
Manually write code to do such a mapping.
Use a tool that will automatically handle this for you.
AutoMapper is an example of 2.
The most common use is to flatten models into a data transfer objects (or, in general, mapping across layer boundaries). What's very nice about AutoMapper is that for common scenarios you don't have to do any configuring (convention over configuration).
Map objects between layers. Good example: Here