Using EF Core 3.1, I'm trying to get a table from the database (SQL Server) using the following code:
query = dbContext.Set<Entity>().ToList();
The code is working for other tables but fails on a specific table with the following exception:
System.InvalidCastException: Unable to cast object of type 'System.Byte' to type 'System.Int32'.
at Microsoft.Data.SqlClient.SqlBuffer.get_Int32()
at Microsoft.Data.SqlClient.SqlDataReader.GetInt32(Int32 i)
at lambda_method(Closure , QueryContext , DbDataReader , ResultContext , Int32[] , ResultCoordinator )
at Microsoft.EntityFrameworkCore.Query.Internal.QueryingEnumerable`1.Enumerator.MoveNext()
at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
Using a breakpoint in a try-catch doesn't help as the inner exception is null. How can I tell which table column is causing the cast exception?
Model code:
[Table("Plugin")]
public partial class Plugin
{
public Plugin()
{
SetAPlugins = new HashSet<SetProfile>();
SetBplugins = new HashSet<SetProfile>();
SetBPlugins = new HashSet<SetProfile>();
SetBPlugins = new HashSet<SetProfile>();
SetBPlugins = new HashSet<SetProfile>();
}
[Key]
[Column("ID")]
public Guid ID { get; set; }
public int Serial { get; set; }
[Column(TypeName = "datetime")]
public DateTime? DateCreated { get; set; }
[Column(TypeName = "datetime")]
public DateTime? DateModified { get; set; }
public ObjectStatus ObjectStatus { get; set; }
[Required]
public byte[] Timestamp { get; set; }
public PluginType Type { get; set; }
[StringLength(64)]
public string Name { get; set; }
[StringLength(512)]
public string ProcessorAssembly { get; set; }
[StringLength(512)]
public string ProcessorClass { get; set; }
[StringLength(512)]
public string AdminAssembly { get; set; }
[StringLength(512)]
public string AdminClass { get; set; }
[StringLength(32)]
public string ConfigName { get; set; }
public ProfileType SubType { get; set; }
[StringLength(256)]
public string ContainerType { get; set; }
[StringLength(256)]
public string SupportedFeatures { get; set; }
[InverseProperty(nameof(SetProfile.SetAPlugin))]
public virtual ICollection<SetProfile> SetAPlugins { get; set; }
[InverseProperty(nameof(SetProfile.SetBplugin))]
public virtual ICollection<SetProfile> SetBPlugins { get; set; }
[InverseProperty(nameof(SetProfile.SetCPlugin))]
public virtual ICollection<SetProfile> SetCPlugins { get; set; }
[InverseProperty(nameof(SetProfile.SetDPlugin))]
public virtual ICollection<SetProfile> SetDPlugins { get; set; }
[InverseProperty(nameof(SetProfile.SetEPlugin))]
public virtual ICollection<SetProfile> SetEPlugins { get; set; }
}
I've attached a screenshot of the DB columns from SSMS.
The problem is
public ObjectStatus ObjectStatus { get; set; }
& The enum must be created as follows:
public enum ObjectStatus : byte
{
//List of values
}
The problem was that the SQL type is tinyint which is a Byte in code and which cannot be implicitly converted to enum. I used the following code to solve this:
[Column("ObjectStatus")]
public Byte objectStatus { get; set; }
[NotMapped]
public ObjectStatus ObjectStatus
{
get
{
if (objectStatus > 0)
return (ObjectStatus)objectStatus;
else
return ObjectStatus.Active;
}
set
{
objectStatus = (Byte)value;
}
}
You are mapping a property as int which should be a byte and only have one property mapped as int, which is Serial, so that should be the one.
Related
System.InvalidCastException: 'Unable to cast object of type 'System.String' to System.DateTime;
I have added below highlighted columns in the existing table:
and when I am getting data, I have got the above exception:
var tempData = _context.Finance.Where(x => x.id == id)
Can anyone please guide, I am using Entity Framework Core. I have the same datatime in model also.
Entity model:
public class Finance
{
[Key]
public int id { get; set; }
public DateTime created_at { get; set; }
public int created_by { get; set; }
public DateTime delivered_date { get; set; }
public int call_origin { get; set; }
public int status { get; set; }
public int sheet_num { get; set; }
public string bank_name { get; set; }
public float bank_deposit_amount { get; set; }
public string department_to_assign { get; set; }
public int receiving_type { get; set; }
public float adjustment_amount { get; set; }
public DateTime adjustment_date { get; set; }
public int adjustment_type { get; set; }
}
Try updating your the model from database.
I faced a similar problem and had to remove the table and re-add to the model.
An exception occurred while reading a database value for property 'EMWH.UniqueAttchID'. The expected type was 'System.Nullable`1[System.Guid]' but the actual value was null.
I'm using EFCore 5.0 and I get the error listed above. If in my EMWH view I hide all records where there is a NULL in UniqueAttchID it works fine. But I can't seem to find a way to exclude the records where the principal key (for the relationship) is NULL. But still have the ability to view all records.
Code causing the error
var workOrder = await _context.EMWHs.AsNoTracking()
.Include(x => x.EMWIs).ThenInclude(x => x.HQATs)
.Where(x => x.KeyID == WorkOrderKeyId).SingleOrDefault();
EMWH
public class EMWH
{
public byte EMCo { get; set; }
public string WorkOrder { get; set; }
public string Equipment { get; set; }
public string? Description { get; set; }
public Guid? UniqueAttchID { get; set; }
[Column("udServiceRecordYN")]
public string? ServiceRecordYN { get; set; }
public char Complete { get; set; }
public long KeyID { get; set; }
[Column("DateSched")]
[Display(Name = "Scheduled Date")]
public DateTime ScheduledDate { get; set; }
public virtual EMEM EMEM { get; set; }
public virtual IEnumerable<EMWI> EMWIs { get; set; }
public virtual IEnumerable<HQAT> HQATs { get; set; }
}
HQAT
public class HQAT
{
public byte HQCo { get; set; }
public string FormName { get; set; }
public string KeyField { get; set; }
public string Description { get; set; }
public string AddedBy { get; set; }
public DateTime? AddDate { get; set; }
public string DocName { get; set; }
public int AttachmentID { get; set; }
public string TableName { get; set; }
public Guid? UniqueAttchID { get; set; }
public string OrigFileName { get; set; }
public string DocAttchYN { get; set; }
public string CurrentState { get; set; }
public int? AttachmentTypeID { get; set; }
public string IsEmail { get; set; }
public long KeyID { get; set; }
public virtual udEMCD EMCD { get; set; }
public virtual HQAF HQAF { get; set; }
public virtual EMWH EMWH { get; set; }
public virtual EMWI EMWI { get; set; }
public virtual udEMED EMED { get; set; }
}
DBContext
modelBuilder.Entity<EMWH>().ToTable("EMWH").HasKey(k=>new { k.EMCo, k.WorkOrder });
modelBuilder.Entity<HQAT>().HasOne(x => x.EMWH).WithMany(x => x.HQATs).HasForeignKey(x => x.UniqueAttchID)
.HasPrincipalKey(x => x.UniqueAttchID);
You have the relationship set up to count on public Guid? UniqueAttchID { get; set; } for keys between entities, but you have this set up as a nullable GUID type, so when the query runs the DB is likely coming across a null value in the table, and can't resolve the relationship. The simple solution and arguably best practice is to make those properties non-nullable, or define the relationship using int or long types as ID's, so they can't be null, and making sure your INSERT and UPDATE queries are properly setting the relationships. Either way, the null is where you should start and if you have records in the tables already that have null values you are expecting to use as keys, you could have some work on your hands to figure out how those are supposed to be linked and getting the nulls replaced with GUID values.
I have my C# Model classes generated from SQL using ADO.net Entity Model.
I created 2 additional classes which are not generated by ADO which have 1 to many relationship.
The class definition is below:
LISToxPatient
[Table("LISToxPatient")]
public class LISToxPatient
{
public LISToxPatient()
{
LISResults = new HashSet<LISResult>();
}
[Key]
public long LISToxPatientID { get; set; }
public long? PatientID { get; set; }
public long? NetworkID { get; set; }
[StringLength(20)]
public string FirstName { get; set; }
[StringLength(20)]
public string LastName { get; set; }
[StringLength(50)]
public string Prescriber { get; set; }
[StringLength(20)]
public string ResultSummary { get; set; }
[StringLength(20)]
public string Specimen { get; set; }
public virtual ICollection<LISResult> LISResults { get; set; }
}
LIS Result
[TableName("LISResult")]
public class LISResult
{
[Key]
public long LISResultID { get; set; }
public long LISToxPatientID { get; set; }
[StringLength(40)]
public string Remark { get; set; }
[StringLength(30)]
public string Compound { get; set; }
[StringLength(20)]
public string CreateBy { get; set; }
[StringLength(20)]
public string UpdateBy { get; set; }
public DateTime? CreateDT { get; set; }
public DateTime? UpdateDT { get; set; }
public bool? Deleted { get; set; } = false;
public virtual LISToxPatient LISToxPatient { get; set; }
}
Now when I try to add "LISToxPatient" object which holds a collection of "LISResult" entities, I get an error which says:
"Invalid object name dbo.LISResults".
I can see that see error is due to the EF trying to find pluralized table name which doesn't exist in db but all my other table classes use the pluralized table name convention. I tried to add this line
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();
but still get the same error.
How can I fix it?
I have came across a problem where i need to map self referencing table from EF6 to DTO.
This is the table :
The Entity looks like this :
public partial class Page
{
public Page()
{
this.ChildPages = new HashSet<Page>();
}
public int PageId { get; set; }
public string Name { get; set; }
public string ModelName { get; set; }
public bool IsList { get; set; }
public bool IsActive { get; set; }
public bool IsDeleted { get; set; }
public System.DateTime DateCreated { get; set; }
public System.DateTime DateModified { get; set; }
public int Order { get; set; }
public Nullable<int> ParentPageId { get; set; }
public virtual ICollection<Page> ChildPages { get; set; }
public virtual Page ParentPage { get; set; }
}
The DTO Model looks like this :
public class PageViewModel
{
public int PageId { get; set; }
public string Name { get; set; }
public string ModelName { get; set; }
public bool IsList { get; set; }
public bool IsActive { get; set; }
public bool IsDeleted { get; set; }
public System.DateTime DateCreated { get; set; }
public System.DateTime DateModified { get; set; }
public virtual ICollection<PageViewModel> ChildPages { get; set; }
public virtual PageViewModel ParentPage { get; set; }
}
Automapper config looks like this:
config.CreateMap<Page, PageViewModel>().MaxDepth(8)
However when I run this code :
var pages = DB.Pages.ProjectTo<PageViewModel>().ToList();
I get the following exception:
An exception of type 'System.NotSupportedException' occurred in
EntityFramework.SqlServer.dll but was not handled in user code
Additional information: The type 'PageViewModel' appears in two
structurally incompatible initializations within a single LINQ to
Entities query. A type can be initialized in two places in the same
query, but only if the same properties are set in both places and
those properties are set in the same order.
Does anyone have an idea how to solve this issue?
I have a statement in one of my entities which uses a foreign key to return an IEnumerable<CustomField>.
I have used LINQ in my repository to test the below method to see if it works and it does. But when I use the foreign key reference in the entity it returns null. Am I missing something here? How can I use a foreign key to gain access to the data in another entity.
Invoice entity:
[Table("vwinvoice")]
public class Invoice
{
[Key]
[DatabaseGenerated(System.ComponentModel.DataAnnotations.Schema.DatabaseGeneratedOption.Identity)]
public int Sys_InvoiceID { get; set; }
[DisplayName("Inc.In Turnover")]
public bool Turnover { get; set; }
public int FK_StatusID { get; set; }
[DisplayName("Invoice No.")]
public string InvoiceNumber { get; set; }
[DisplayName("Invoice Date")]
public DateTime InvoiceDate { get; set; }
[DisplayName("Document Type")]
public string DocType { get; set; }
[DisplayName("Supplier Invoice No.")]
[Column("SupplierInvoiceNumber")]
public string SuppInvNumber { get; set; }
public int FK_SupplierID { get; set; }
[DisplayName("Account Number")]
public string AccountNumber { get; set; }
[DisplayName("Order Number")]
public string OrderNumber { get; set; }
[DisplayName("Order Date")]
public DateTime? OrderDate { get; set; }
[DisplayName("Currency Code_Doc")]
public string CurrencyCode_Doc { get; set; }
[DisplayName("Net Amount_Doc")]
public decimal? NetAmount_Doc { get; set; }
[DisplayName("VAT Amount_Doc")]
public decimal? VATAmount_Doc { get; set; }
[DisplayName("Gross Amount_Doc")]
[Required]
public decimal? GrossAmount_Doc { get; set; }
[DisplayName("Currency Code_Home")]
public string CurrencyCode_Home { get; set; }
[DisplayName("Net Amount_Home")]
public decimal? NetAmount_Home { get; set; }
[DisplayName("VAT Amount_Home")]
public decimal? VATAmount_Home { get; set; }
[DisplayName("Gross Amount_Home")]
public decimal? GrossAmount_Home { get; set; }
[DisplayName("Payment Reference")]
public string PaymentReference { get; set; }
[DisplayName("Supplier")]
public string AccountName { get; set; }
[DisplayName("Status")]
public string StatusName { get; set; }
[DisplayName("Auditor Comments")]
public string AuditorComments { get; set; }
[DisplayName("Reviewer Comments")]
public string ReviewerComments { get; set; }
[DisplayName("Data Source")]
[Required]
public string DataOrigin { get; set; }
public int DetailLineCount { get; set; }
public IEnumerable<CustomField> ClientData {
get {
//Use the CustomFields foreign key to gain access to the data returns null.
return GetCustomFieldData(this.CustomFields.Select(r => r));
}
}
private IEnumerable<CustomField> GetCustomFieldData(IEnumerable<Entities.CustomFields> enumerable) {
return (from f in enumerable
select new CustomField {
Name = f.FK_CustomHeader,
Value = f.Value
});
}
//Custom Field Additions
public virtual ICollection<CustomFields> CustomFields { get; set; }
}
CustomFields entity:
[Table("tblCustomFields")]
public class CustomFields
{
[Key]
public int ID { get; set; }
public int? FK_SysInvoiceID { get; set; }
[StringLength(255)]
public string FK_CustomHeader { get; set; }
[StringLength(255)]
public string Value { get; set; }
public virtual Invoice Invoices { get; set; }
public virtual CustomFieldHeaders CustomFieldHeaders { get; set; }
}
I also cannot place a breakpoint in the get statement to see what happens, why is this? It just skips over the breakpoint whenever I try to return a list of Invoices, which can be seen here:
public IQueryable<Invoice> Invoices
{
get
{
var x = _ctx.Invoices.ToList();
return _ctx.Invoices;
}
}
You are using the virtual keyword when declaring your CustomFields property. As such it will be lazy loaded. If you want the property to be populated once returned from the repository you will need to explicitly Include the table in your method:
var x = _ctx.Invoices.Include(i => i.CustomFields).ToList();
return _ctx.Invoices;
Or you can remove the virtual keyword and the property will always be populated, with the consequent performance hit of the database join and the extra data being returned whenever you access Invoices.