How to deal with Database Column with DEFAULT value in SPA(ASP.NET MVC SPA) - asp.net

Code First Class:
public class Product
{
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int ProductId{ get; set; }
[MaxLength(256), Required]
public string ProductName { get; set; }
public DateTime CreatedTime { get; set; }
}
In the database, i give the CreatedTime Column the DEFAULT value "(getdate())",
so that the database will generate a value for us on insert operation.
My Question:
Is there some kind of DataAnnotations/something else that can do the following things:
can tell Entity Framework(Code First Mode) to include CreateTime when Building up the Database;
can tell EF NOT to include CreateTime when Inserting a new column into the Database;
can tell EF to retrieve back all the columns including CreateTime when Selecting from the database.
So that, I can treat the CreatedTime Column in the Client Side the same as the ProductId Column(which is the Identity Column: value Only can be generated by the Database; will NOT be included when Inserting a new column; will be included when Selecting...).
I think it's much more clear now, sorry for the misunderstanding!
Dean

Related

How to diagnose slow Entity Framework stored procedure call?

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!

SQLite-Net Extensions | Foreign Key Reference to same entity

I am facing an issue in using SQLite-Net Extensions to save data in local DB in scenario where the foreign key is referencing the same entity (self-join).
Example – Employee and Manager. Every employee has a manager and a manager is also an employee. I am facing issues in saving data in such cases. It will be really helpful if you can provide some insights. Does this extension support this kind of relationship?
Yes, relationships between objects of the same class are supported, but the foreign keys and inverse properties must be explicitly specified in the relationship property attribute because the discovery system will get it wrong as there are be two relationships with the same type.
This example is extracted from the project readme:
public class TwitterUser {
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public string Name { get; set; }
[ManyToMany(typeof(FollowerLeaderRelationshipTable), "LeaderId", "Followers",
CascadeOperations = CascadeOperation.CascadeRead)]
public List<TwitterUser> FollowingUsers { get; set; }
// ReadOnly is required because we're not specifying the followers manually, but want to obtain them from database
[ManyToMany(typeof(FollowerLeaderRelationshipTable), "FollowerId", "FollowingUsers",
CascadeOperations = CascadeOperation.CascadeRead, ReadOnly = true)]
public List<TwitterUser> Followers { get; set; }
}
// Intermediate class, not used directly anywhere in the code, only in ManyToMany attributes and table creation
public class FollowerLeaderRelationshipTable {
public int LeaderId { get; set; }
public int FollowerId { get; set; }
}
As you can see here we have a many-to-many between Twitter users. In your case it will be a one-to-many, so you won't need the intermediate table and you'll need the foreign key (ManagerId for example) in your Person class.

EF is not cascade deleting

The problem is i cannot perform cascade deletion using only EF codefirst conventions. They, in particular, say: "If a foreign key on the dependent entity is not nullable, then Code First sets cascade delete on the relationship"
I have parent and child entities:
[Table("AssociationPages")]
public class AssociationPage
{
[Column("AssociationPageID"), Required, Key]
public int Id { get; set; }
[Required, ForeignKey("AssociationSetting")]
public int AssociationId { get; set; }
public virtual AssociationSetting AssociationSetting { get; set; }
}
[Table("AssociationSetting")]
public class AssociationSetting
{
[Required, Key, DatabaseGenerated(DatabaseGeneratedOption.None)]
public int AssociationId { get; set; }
public virtual ICollection<AssociationPage> Pages { get; set; }
}
My AssociationPages table in MS SQL Server looks like:
CREATE TABLE [dbo].[AssociationPages](
[AssociationPageID] [int] IDENTITY(1,1) NOT NULL,
[AssociationId] [int] NOT NULL,
...
)
and a FK (but it shouldnt matter as EF has its own conventions):
ALTER TABLE [dbo].[AssociationPages] WITH CHECK ADD CONSTRAINT [FK_ChamberPages_Chambers] FOREIGN KEY([AssociationId])
REFERENCES [dbo].[AssociationSetting] ([AssociationId])
GO
So i have non-nullable FK everywhere but once i try to delete parent AssociationSetting row then getting the "The DELETE statement conflicted with the REFERENCE constraint FK_ChamberPages_Chambers. The conflict occurred in database ..., table dbo.AssociationPages, column AssociationId message". I know i can set constraints inside database or with EF fluent API but why this is not working?
Thanks for your ideas!
update
WillCascadeOnDelete() doesnt work as well :(
It may be that Code First is not setting up the cascade since you are not following the naming conventions.
Try this:
public class AssociationPage
{
public int Id { get; set; }
public int AssociationSettingId { get; set; }
public virtual AssociationSetting AssociationSetting { get; set; }
}
public class AssociationSetting
{
public int Id { get; set; }
public virtual ICollection<AssociationPage> Pages { get; set; }
}
Okay, in investigation purposes i created a simpliest parent-child tables, put two rows - one per table, created FK relationship as "No Action" on cascade delete and wrote EF Code First entities.
Then I set up FK relationship variuos ways - via column attributes, Fluent API, explicitly specifying WillDeleteOnCascade() method or alltogether but had no luck trying to delete parent row. The only way I achieved this when retrieved both parent and child records prior to removing. At this point SQL profiler shown that rows being deleted one by one both for parent and children tables.
Summarizing the above I suppose the cascading in EF Code First means the setting constraints on the database being created by EF. I might be missing something thu.

Two foreign keys to same primary table

I have two classes: Customer and Association.
A customer can have an association with many customers. Each association is of a defined type (Family, Friend, etc) i.e Customer A is a friend of Customer B. Customer A is related to Customer C. The type of association is defined by an enum AssociationType.
In order to create this in EF i've defined the following classes
public class Customer
{
public string FirstName {get; set;}
public string LastName {get; set;}
public virtual ICollection<Association> Associations { get; set; }
}
public class Association
{
public int CustomerId { get; set; }
public virtual Customer Customer { get; set; }
public int AssociatedCustomerId { get; set; }
public virtual Customer AssociatedCustomer { get; set; }
public AssociationType AssociationType { get; set; }
}
I've removed the Data Annotations as I was unable to get this to compile. I get the error:
"Model compatibility cannot be checked because the database does not
contain model metadata".
Does anyone have any ideas?
It happens sometimes when an error occurs during database creation. The database schema is created then - except the __MigrationHistory table. When you run your application again EF wants to check against the __MigrationHistory table if the schema is still up-to-date with the model and if that table doesn't exist it throws the exception you are having.
To fix the problem either delete the database manually or set the initializer to DropCreateDatabaseAlways<MyContext> (with Database.SetInitializer(new DropCreateDatabaseAlways<MyContext>()) - only once. After the DB is created set it back to your original initializer.
BTW: For your model you will have to specify explicitly that Customer.Associations is related to Association.Customer, either with data annotations...
[InverseProperty("Customer")]
public virtual ICollection<Association> Associations { get; set; }
...or with Fluent API:
modelBuilder.Entity<Customer>()
.HasMany(c => c.Associations)
.WithRequired(a => a.Customer)
.HasForeignKey(a => a.CustomerId);
Thank you Slauma,
your answer got us going in the right direction.
We added the following configuration to the Association configuration:
HasRequired(x => x.AssociatedCustomer).WithMany().WillCascadeOnDelete(false);

What's Automapper for?

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

Resources