Not generating unique GUID - asp.net

I got a very weird event when storing data.
My table uses Guid as primary ID, and for some reason it is recording the same Guid for all new entries.
Table constructs
public class Checkpoint
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public string Title { get; set; }
public DateTime? CreatedOn { get; set; }
public DateTime? ModifiedOn { get; set; }
}
public class Track
{
public Track()
{
Checkpoints = new List<Checkpoint>();
}
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid Id { get; set; }
[Required]
public List<Checkpoint> Checkpoints { get; set; }
public DateTime? CreatedOn { get; set; }
public DateTime? ModifiedOn { get; set; }
}
Code snippet that converts from model to list of new Checkpoints stored in track.
var trackObject = new Track();
var checkpointList = model.Checkpoints.ConvertAll(x => new Checkpoint {Title = x.Title});
trackObject.Checkpoints.Add(checkpointList);
db.Track.Add(trackObject);
await db.SaveChangesAsync();
Checkpoint table result (i omited the foreign key pointing to Track object):
ID | TITLE | CREATED_ON
--------------------------------------------------------------------------------
c3451b2b-bb30-e711-b867-f01faf23929d | First | 4/05/2017 11:16:50 AM
c5451b2b-bb30-e711-b867-f01faf23929d | Second | 4/05/2017 11:16:50 AM
c6451b2b-bb30-e711-b867-f01faf23929d | Third | 4/05/2017 11:16:50 AM
c7451b2b-bb30-e711-b867-f01faf23929d | Sprint | 4/05/2017 11:16:50 AM
c8451b2b-bb30-e711-b867-f01faf23929d | Home | 4/05/2017 11:16:50 AM
c9451b2b-bb30-e711-b867-f01faf23929d | Finish | 4/05/2017 11:16:50 AM
As can be seen all the ID fields are the same.
Where is the fault in the code?

These are all unique and different. Look at the second digit of these posted guids.
The EF code tells SQL to generate new Sequential Guids (TSQL NEWSEQUENTIALID()).
https://learn.microsoft.com/en-us/sql/t-sql/functions/newsequentialid-transact-sql

Related

ef core shared child table with one-to-many

I would like to have a shared table that can be somehow referenced to multiple parent tables. The parent tables can have multiple rows from the shared Attachement table. The Type/TypeId would be a column which points to the parent table (like if the parentId is in Person or Company table)
Shared table:
Id | ParentId | Type/TypeId | Value
1 1 Person/1 "somestringvalue"
2 1 Person/1 "another value"
3 3 Company/2 "value"
....
The models would look something like this
public class Attachement
{
[Key]
public int Id { get; set; }
//PK- Id of the parent table
public int ParentId { get; set; }
// type or enum of a parent table. Should point to which table it points to
public int Type { get; set; }
public string Value { get; set; }
}
public class Person
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
//shared table
public ICollection<Attachement> Attachements { get; set; }
}
public class Company
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
//shared table
public ICollection<Attachement> Attachements { get; set; }
}
Sidenote also - im using code first pattern.
Thanks!

Entity Framework Core + MariaDB - Navigation Property is null

I have a many-to-many relationship defined using a table in MariaDB. I am trying to use Navigation Properties in Entity Framework Core for the related entities, but they're not hydrated.
roles
| role_id | role_name |
| 1 | Role-A |
| 2 | Role-B |
groups
| group_id | group_name |
| 1 | Group-A |
| 2 | Group-B |
role_to_group
| role_to_group_id | role_id | group_id |
| 1 | 1 | 1 |
| 2 | 2 | 1 |
| 3 | 2 | 2 |
This is the class
[Table(name: "role_to_group")]
public class RoleToGroup
{
[Column(name: "role_to_group_id")]
public long RoleToGroupId { get; set; }
[Column(name: "role_id")]
[ForeignKey("RGToRoles")]
public int RoleId { get; set; }
[Column(name: "group_id")]
public int UserGroupId { get; set; }
[Include]
public Role Role { get; set; }
[Include]
public UserGroup UserGroup { get; set; }
}
The [Include] is a custom defined attribute for hydrating the navigation properties using the pattern similar to DbContext.Set<T>().Include("property_name") via an extension method that does reflection on T and finds all properties with the attribute [Include] defined on them.
However, I am unable to get this to work correctly. The navigation properties Role and UserGroup return null.
What do you suggest I am doing wrong? Also please let me know if you need any more details to be added to the question!!
The problem might be that EF Core doesn't automatically do lazy loading. ( Documentation about how to implement lazy loading ).
When installed these NuGet packages:
Microsoft.EntityFrameworkCore.Proxies
Microsoft.EntityFrameworkCore.Relational
and enabled lazy loading as e.g.:
public class MyDbContext : DbContext
{
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseMySQL(#"User Id=root;Host=localhost;Database=Test;");
optionsBuilder
.UseLazyLoadingProxies();
}
public DbSet<UserGroup> UserGroups { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<RoleToGroup> RoleToGroups { get; set; }
}
I got it loaded:
using (var context = new MyDbContext())
{
var roleGroup1 = context.RoleToGroups.First();
Console.WriteLine(roleGroup1.Role.Name); //Role-A
Console.WriteLine(roleGroup1.UserGroup.Name); //Group-A
}
Lazy loading requires types to be public, and properties to be lazy-loaded must be virtual:
[Table(name: "role_to_group")]
public class RoleToGroup
{
[Column(name: "role_to_group_id")]
public int RoleToGroupId { get; set; }
[Column(name: "role_id")]
[ForeignKey("roles")]
public int RoleId { get; set; }
[Column(name: "group_id")]
[ForeignKey("groups")]
public int UserGroupId { get; set; }
public virtual Role Role { get; set; } //must be virtual
public virtual UserGroup UserGroup { get; set; }//must be virtual
}
[Table(name: "roles")]
public class Role
{
[Key]
[Column(name: "role_id")]
public int RoleId { get; set; }
[Column(name: "role_name")]
public string Name { get; set; }
}
[Table(name: "groups")]
public class UserGroup
{
[Key]
[Column(name: "group_id")]
public int GroupId { get; set; }
[Column(name: "group_name")]
public string Name { get; set; }
}
Alternatively to lazy loading, manual Eager or Explicit loading could be used from the same doc.

asp.net - LINQ Query with relational Data

I have two tables Category and Document. See relationships in picture
See picture
I wrote the following query to select data from both tables based on relationship
public List<DocumentViewModel> All()
{
var docs = _context.Document.ToList();
List<DocumentViewModel> docList = docs.Select(x => new DocumentViewModel
{ DocumentId = x.DocumentId,
DocumentPath = x.DocumentPath,
CategoryId = x.CategoryId,
CategoryName = x.Category.CategoryName }).ToList();
return docList;
}
when this function is called , I get the following error
System.NullReferenceException: 'Object reference not set to an instance of an object.'
Here are my modals
document
public class Document
{
[Key]
public int DocumentId { get; set; }
[Required]
public string DocumentPath { get; set; }
public Nullable<int> CategoryId { get; set; }
public virtual Category Category { get; set; }
}
Category
public class Category
{
[Key]
public int CategoryId { get; set; }
[Required]
public string CategoryName { get; set; }
public virtual ICollection<Document> Documents { get; set; }
}
DocumentViewModel
public class DocumentViewModel
{
public int DocumentId { get; set; }
public string DocumentPath { get; set; }
public int? CategoryId { get; set; }
public string CategoryName { get; set; }
}
Any Idea where am doing mistake?
In this case there is no reason to get a List in memory and then do the projection, you can do this directly from EF instead. Even if there is no relationship defined EF will return null for CategoryName if you project the the results. If you go to memory first then an NRE is expected if there is no Category relationship.
public List<DocumentViewModel> All()
{
return _context.Document.Select(x => new DocumentViewModel
{ DocumentId = x.DocumentId,
DocumentPath = x.DocumentPath,
CategoryId = x.CategoryId,
CategoryName = x.Category.CategoryName}).ToList();
}
Original reason why it is failing.
There is at least one entity that does not have a corresponding relationship with Category.
You do not have lazy loading enabled (which is a good thing) and if that is the case you should use Include to return the relationship.

Display the sum of the orders of the month in chart

I don`t know how to display, at the beginning the sum of the orders of the month in the table in the asp.net MVC.
My data in table Order look like:
DateCreated | TotalPrice
2017-02-06 | 400
2017-02-06 | 300
2017-03-06 | 100
2017-03-06 | 50
And I want to get mountly sum of TotalPrice, like this:
DateCreated | TotalPrice
2017-02 | 700
2017-03 | 150
My model class Order:
public int orderId { get; set; }
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
[StringLength(100)]
public string firstName { get; set; }
[StringLength(150)]
public string lastName { get; set; }
[StringLength(150)]
public string address { get; set; }
[StringLength(20)]
public string phoneNumber { get; set; }
public string email { get; set; }
public string comment { get; set; }
public DateTime dateCreated { get; set; }
public OrderState orderState { get; set; }
public decimal totalPrice { get; set; }
public List<OrderIteam> OrderIteams { get; set; }
I try to write something like this to display the sum of the orders of the month in the table :
public ActionResult ListOrder()
{
var result =
from s in db.Orders
group s by new { date = new DateTime(s.dateCreated.Year, s.dateCreated.Month, 1) } into g
select new
{
dateCreated = g.Key.date,
sumTotalPrice = g.Sum(x => x.totalPrice)
};
return View(result);
}
My view looks like this
I am getting the error message:
The model item passed into the dictionary is of type 'System.Data.Entity.Infrastructure.DbQuery1[<>f__AnonymousType52[System.DateTime,System.Decimal]]', but this dictionary requires a model item of type 'System.Collections.Generic.IEnumerable`1[Sklep_Internetowy.Models.Order]'.
At the end I would like to show that the sum of the orders of a given month as the chart below:
Chart
Currently the LINQ query below returns DbQuery instance with anonymous type instead of IEnumerable collection:
var result = from s in db.Orders
group s by new { date = new DateTime(s.dateCreated.Year, s.dateCreated.Month, 1) } into g
select new
{
dateCreated = g.Key.date,
sumTotalPrice = g.Sum(x => x.totalPrice)
}; // returns System.Data.Entity.Infrastructure.DbQuery<AnonymousTypeN>
The reason behind thrown InvalidOperationException here is simply because a different type of data has been passed into the view which requires IEnumerable<Sklep_Internetowy.Models.Order>.
Try change return type to Order instead using anonymous type one:
var result = from s in db.Orders
group s by new { date = new DateTime(s.dateCreated.Year, s.dateCreated.Month, 1) } into g
select new Order // return Sklep_Internetowy.Models.Order here
{
dateCreated = g.Key.date,
sumTotalPrice = g.Sum(x => x.totalPrice)
};
At this point, the return type of LINQ query above becomes IQueryable<Sklep_Internetowy.Models.Order> which implements IEnumerable, hence it doesn't require conversion (but you may still need to use collection aggregate methods to execute it, e.g. ToList()).
Related issues:
The model item passed into the dictionary is of type 'System.Data.Entity.Infrastructure.DbQuery', but this dictionary requires a model item of type B
The model item passed into the dictionary is 'System.Data.Entity.Infrastructure.DbQuery`, but requires 'System.Collections.Generic.IEnumerable

EF 5, one to many, more than one table

I'm having a little of trouble with the following classes:
public class TwoVariableDetails
{
public TwoVariableDetails()
{
MovementsPerBlocks = new HashSet<MovementsRow>();
MovementsPerShiftTypes = new HashSet<MovementsRow>();
MovementsPerMachines = new HashSet<MovementsRow>();
MovementsPerShifts = new HashSet<MovementsRow>();
}
[Key]
public Guid TwoVariableDetailsId { get; set; }
[Required]
[MaxLength(50)]
public string Name { get; set; }
[Required]
[MaxLength(1000)]
[DataType(DataType.MultilineText)]
public string Description { get; set; }
public virtual ICollection<MovementsRow> MovementsPerBlocks { get; set; }
public virtual ICollection<MovementsRow> MovementsPerShiftTypes { get; set; }
public virtual ICollection<MovementsRow> MovementsPerMachines { get; set; }
public virtual ICollection<MovementsRow> MovementsPerShifts { get; set; }
}
[Table("Movement")]
public class MovementsRow
{
public MovementsRow()
{
MovementsCells = new HashSet<MovementsCell>();
}
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[CsvField(Ignore = true)]
public Guid MovementId { get; set; }
[Required]
public int RowNo { get; set; }
[Required]
[CsvField(Ignore = true)]
public Guid ModelId { get; set; }
[ForeignKey("ModelId")]
[CsvField(Ignore = true)]
public virtual TwoVariableDetails Model { get; set; }
[TypeConverter(typeof(MovementsCellTypeConverter))]
public virtual ICollection<MovementsCell> MovementsCells { get; set; }
}
[Table("MovementCell")]
public class MovementsCell
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[CsvField(Ignore = true)]
public Guid CellId { get; set; }
[Required]
public int ColumnNo { get; set; }
[Required]
public int Count { get; set; }
[Required]
[CsvField(Ignore = true)]
public Guid MovementId { get; set; }
[ForeignKey("MovementId")]
[CsvField(Ignore = true)]
public virtual MovementsRow Model { get; set; }
}
When I try to save it to the database I get the following error:
The INSERT statement conflicted with the FOREIGN KEY constraint "FK_dbo.Movement_dbo.TwoVariableDetails_ModelId". The conflict occurred in database "aspnet-GreenCranes.UI-20130516", table "dbo.TwoVariableDetails", column 'TwoVariableDetailsId'.
The statement has been terminated.
This is the code I'm using for saving:
twoVariableDetails.TwoVariableDetailsId = Guid.NewGuid();
_context.TwoVariableDetailsModels.Add(twoVariableDetails);
_context.SaveChanges();
My table looks like this:
Movement
- Column
- MovementId
- RowNo
- ModelId(FK, uniqueidentifier, not null)
- TwoVariableDetails_TwoVariableDetailsId(FK, uniqueidentifier, null)
- TwoVariableDetails_TwoVariableDetailsId2(FK, uniqueidentifier, null)
- TwoVariableDetails_TwoVariableDetailsId3(FK, uniqueidentifier, null)
- TwoVariableDetails_TwoVariableDetailsId4(FK, uniqueidentifier, null)
- Keys
- FK_dbo.Movement_dbo.TwoVariableDetails_ModelId
- FK_dbo.Movement_dbo.TwoVariableDetails_TwoVariableDetails_TwoVariableDetailsId
- FK_dbo.Movement_dbo.TwoVariableDetails_TwoVariableDetails_TwoVariableDetailsId1
- FK_dbo.Movement_dbo.TwoVariableDetails_TwoVariableDetails_TwoVariableDetailsId2
- FK_dbo.Movement_dbo.TwoVariableDetails_TwoVariableDetails_TwoVariableDetailsId3
I'm not sure what is the problem with my approach. Should I change the MovementsRow class to have four Model properties and four modelid fk and then use InverseProperty attribute?
MovementsRow.Model belongs to another relationship than the four collections in TwoVariableDetails. That's the reason why you don't have four, but five foreign keys in the database table. When you insert twoVariableDetails into the DB and it contains a MovementRow instance in one of the collections EF expects that its ModelId is set to a Guid that references an existing TwoVariableDetails row - which it doesn't apparently. Hence the exception.
Should I change the MovementsRow class to have four Model properties
and four modelid fk and then use InverseProperty attribute?
I'd say yes. It's probably the best solution. The alternative is to have no Model property at all in MovementRow. It's working but you would not be able to navigate from MovementRow to TwoVariableDetails then.
Your FK_dbo.Movement_dbo.TwoVariableDetails_ModelId is being violated, simply put - the ModelId that the Movement record is using doesn't yet exist in TwoVariableDetails.
If you wanted to keep it simple, and transactional, then you could use TransactionScope along with your database context, save the TwoVariableDetails first in the transaction, and then the records that relate back to it:
using (var context = new MyDbContext())
using (var tranScope = new TransactionScope(TransactionScopeOption.Required) {
// don't save the Movement records yet
twoVariableDetails.TwoVariableDetailsId = Guid.NewGuid();
_context.TwoVariableDetailsModels.Add(twoVariableDetails);
_context.SaveChanges();
// now create the movement records, add them to twoVariableDetails
...
_context.SaveChanges();
// commit the transaction
scope.Complete();
}

Resources