My problem: When using this extension it only maps up the ID value from the database to class object.
So I'm curious how do i make it map the other values?
C# Mapper
public class SoftwareReleaseTypeHandle : SqlMapper.TypeHandler<SoftwareRelease>
{
public override SoftwareRelease Parse(object value)
{
if (value == null || value is DBNull)
{
return null;
}
SoftwareRelease rel = new SoftwareRelease();
rel.ID = (Guid)value;
return rel;
}
public override void SetValue(IDbDataParameter parameter, SoftwareRelease value)
{
parameter.DbType = DbType.Guid;
parameter.Value = value.ID.ToString();
}
}
The SQL table looks like this:
CREATE TABLE [dbo].[SoftwareRelease](
[ID] [uniqueidentifier] NOT NULL,
[Type] [tinyint] NOT NULL,
[ReleaseType] [tinyint] NOT NULL,
[Version] [nchar](30) NOT NULL,
[ZipFile] [varbinary](max) NOT NULL,
[Date] [datetime] NOT NULL
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
The reason i used this mapper was so in other places in my code i could do, and it would automaticly get mapped up:
class MyInstallation
{
public string Bla;
public string BlaBla;
SoftwareRelease MyInstallation;
}
And when i then use Dapper to get from a table that looks like.
CREATE TABLE [dbo].[MyInstallation](
[ID] [uniqueidentifier] NOT NULL,
[Bl] [nchar](30) NOT NULL,
[BlaBla] [nchar](30) NOT NULL,
[MyInstallation] [uniqueidentifier] NOT NULL,
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
Dapper type handlers are intended to map a single column value in your database to a single member in your POCO. They are used for types that Dapper's core doesn't understand - generally anything that isn't a .NET core type.
You don't say exactly what you need to do but if you're just trying to read SoftwareRelease rows from the database then you can simply do the following:
myDb.Query<SoftwareRelease>("SELECT * FROM SoftwareRelease");
Update
Sounds like what you really want is multi-mapping. If you have the following query:
SELECT a.Bla, a.BlaBla, b.*
FROM MyInstallation a
INNER JOIN SoftwareRelease b ON a.SoftwareReleaseId = b.ID
Then you can use the following to populate the object:
myDB.Query<MyInstallation, SoftwareRelease, MyInstallation>(
sql,
(installation, softwareRelease) => {
installation.SoftwareRelease = softwareRelease;
});
Related
I try to add new record :
entity.Id = Id;
_bdc.EquifaxAnswers.Add(entity);
_bdc.SaveChanges();
and Id has exactly defined as primary key and Id in code has value ( unique for table).
And EF create sql code for add record:
INSERT [dbo].[EquifaxAnswers]([FileName], [dtSend], [dtDateTime], [RecordsAll], [RecordsCorrect],
[RecordsIncorrect], [ResendedId], [dtEmailAbout], [StartDate], [EndDate])
VALUES (#0, #1, #2, NULL, NULL, NULL, NULL, NULL, #3, #4)
And as we can see there Id does not exist, so _bdc.SaveChanges();create Exception:
Failed in 25 ms with error: Cannot insert the value NULL into column 'Id', table 'Equifax.dbo.EquifaxAnswers'; column does not allow nulls. INSERT fails.
Primary key definition:
public partial class EquifaxAnswers
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
Why EF don't add Id to INSERT and how to resolve this problem ?
UPD:
Table definition script in database:
CREATE TABLE [dbo].[EquifaxAnswers](
[Id] [int] NOT NULL,
[FileName] [nvarchar](300) NOT NULL,
[dtSend] [datetime] NOT NULL,
[dtDateTime] [datetime] NULL,
[RecordsAll] [int] NULL,
[RecordsCorrect] [int] NULL,
[RecordsIncorrect] [int] NULL,
[ResendedId] [int] NULL,
[dtEmailAbout] [datetime] NULL,
[StartDate] [datetime] NULL,
[EndDate] [datetime] NULL,
CONSTRAINT [PK_EquifaxAnswers] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
You have specified DatabaseGeneratedOption.None
This means that EF is not expecting the database to generate the Id field, and that you should specify the Id field yourself.
If you want the database to generate the Id field automatically, then alter the column to be an IDENTITY type, and change the code to DatabaseGeneratedOption.Identity
Solution:
modelBuilder.Entity<EquifaxAnswers>()
.Property(a => a.Id)
.HasDatabaseGeneratedOption(DatabaseGeneratedOption.None);
If this doesn't work - just uninstall and install again all EF packages ( I don't know why - but this is work for me) for all dependent projects , latest stable version of course.
Reasons:
By convention, EF will assume that primary key properties are automatically generated. So we need to say EF that we will do it by our code. However,this is not clear why doesn't work DataAnnotations like this:
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int Id { get; set; }
but fluent API is working well. Perhaps the reason is that I use both.
I have a table for comments where I can add records in n levels, it means that I can have a comment that it is in the nth level of reply of a comment.
My problem is that how can I dynamically select n levels of comment using linq?
For example I want comments reply for 5th level or 2nd or nth.
Here is my table
public partial class {
public Comment()
{
this.Comments1 = new HashSet<Comment>();
}
public int CommentId { get; set; }
public Nullable<int> ParentId { get; set; }
public string Title { get; set; }
public virtual ICollection<Comment> Comments1 { get; set; }
public virtual Comment Comment1 { get; set; }
}
till now i use linq and call this function in sql-server to get all the children :
[DbFunction("Ents", "cmTree")]
public virtual IQueryable<ContentComment> cmTree(string topLevelComments)
{
var topLevelCommentsParameter = topLevelComments != null ?
new ObjectParameter("topLevelComments", topLevelComments) :
new ObjectParameter("topLevelComments", typeof(string));
return ((IObjectContextAdapter)this).ObjectContext.CreateQuery<ContentComment>("[Entities].[cmTree](#topLevelComments)", topLevelCommentsParameter);
}
an then in sql-server:
ALTER FUNCTION [dbo].[cmTree]
(
-- Table types seems goods here.
-- but in application-level, linq to sql technology dose not support table types.
-- TupleValue type can user for future use.
#topLevelComments NVARCHAR(max)
)
RETURNS #resultTable TABLE (
[Id] [bigint] primary KEY NOT NULL,
[AuthorUserId] [int] NULL,
[AuthorName] [nvarchar](128) NULL,
[AuthorEmail] [nvarchar](256) NULL,
[AuthorUrl] [nvarchar](512) NULL,
[AuthorIp] [nvarchar](100) NULL,
[InsertDateTime] [datetime] NOT NULL,
[BodyContent] [nvarchar](max) NOT NULL,
[IsApproved] [bit] NOT NULL,
[IsAlertable] [bit] NOT NULL,
[ContentId] [bigint] NOT NULL,
[ParentCommentId] [bigint] NULL,
[VerifierUserID] [int] NULL,
[VerifyDateTime] [datetime] NULL,
[Status] [bit] NOT NULL,
[LastModifierUserId] [int] NULL,
[LastModifiedDateTime] [datetime] NULL
)
AS
BEGIN
with CommentTableExpression As (
-- Anchor entities
select rC.Id, rc.AuthorUserId, rc.AuthorName, rc.[AuthorEmail], rc.[AuthorUrl], rc.[AuthorIp], rc.[InsertDateTime], rc.[BodyContent], rc.[IsApproved], rc.[IsAlertable], rc.[ContentId], rc.[ParentCommentId], rc.[VerifierUserID], rc.[VerifyDateTime], rc.[Status], rc.[LastModifierUserId], rc.[LastModifiedDateTime]
from dbo.ContentComments as rC
WHERE rc.ParentCommentId IN (SELECT * FROM dbo.CSVToTable(#topLevelComments))
union all
-- Recursive query execution
select child.Id, child.AuthorUserId, child.AuthorName, child.[AuthorEmail], child.[AuthorUrl], child.[AuthorIp], child.[InsertDateTime], child.[BodyContent], child.[IsApproved], child.[IsAlertable], child.[ContentId], child.[ParentCommentId], child.[VerifierUserID], child.[VerifyDateTime], child.[Status], child.[LastModifierUserId], child.[LastModifiedDateTime]
from dbo.ContentComments as child
inner join CommentTableExpression as t_Comment
on child.ParentCommentId = t_Comment.Id
where child.ParentCommentId is not NULL) -- commente contet=nt budan barasi shavad.
INSERT #resultTable Select * from CommentTableExpression
RETURN
END
Any help would be appreciated..
It will be better to manage one more field in the table called "ChildLevel" and add reply level in that field.
But if you want to use same structure and want to manage then below linq will get 5th level children
var rec = dt.Comments().Where(t => t.Comment1 != null
&& t.Comment1.Comment1 != null
&& t.Comment1.Comment1.Comment1 != null
&& t.Comment1.Comment1.Comment1.Comment1 != null );
I am interested in sorting a query using entity framework and am having trouble sorting using a dynamic order by expression,
I have a parent record (DatasetRecord) with a one to many relationship consisting of a number of associated values (DatasetValues), I would like to be able to sort based on the data stored within the value if it matches a certain field,
So I need to sort by the Value of DatasetValues where it matches a supplied FieldID
public IEnumerable<DatasetRecordDto> FetchData(ModuleSettingsDto settings)
{
var query = _context.DatasetRecords.AsQueryable().Where(r => r.DatasetId == settings.DatasetId && r.IsDeleted == false);
foreach (var filter in settings.Filters)
{
// this works fine, check we have current field and value matches
query = query.Where(i => i.DatasetValues.Any(x => x.DatasetFieldId == filter.DatasetFieldId && x.Value == filter.Value));
}
foreach (var sort in settings.Sort)
{
switch (sort.SortDirection)
{
case "asc":
// THIS IS WHERE I NEED THE DYNAMIC ORDER BY EXPRESSION,
// THIS SHOULD SORT BY DATETIME WHERE FIELD ID MATCHES
query = query.OrderBy(i => i.DatasetValues.Any(x => x.ValueDateTime && x.DatasetFieldId == sort.DatasetFieldId));
break;
}
}
return ShapeResults(query);
}
And here is my database schema:
CREATE TABLE [dbo].[DatasetRecords](
[Id] [int] IDENTITY(1,1) NOT NULL,
[DatasetId] [int] NOT NULL
)
CREATE TABLE [dbo].[DatasetFields](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Label] [varchar](50) NOT NULL,
[DatasetId] [int] NULL,
[DataType] [int] NOT NULL
)
CREATE TABLE [dbo].[DatasetValues](
[Id] [int] IDENTITY(1,1) NOT NULL,
[DatasetRecordId] [int] NOT NULL,
[DatasetFieldId] [int] NOT NULL,
[ValueString] [varchar](8000) NULL,
[ValueInt] [int] NULL,
[ValueDateTime] [datetime] NULL,
[ValueDecimal] [decimal](18, 2) NULL,
[ValueBit] [bit] NULL
)
Please let me know if you need any further info, any help is greatly appreciated,
UPDATE: I am not having an issue with creating a dynamic order by expression, I am trying to apply a conditional sort order for parent records based on the values in a child table
Have you tried running the Linq code on something like LinqPad, it lets you run Linq code against a dataset and shows you the generated SQL. You can take that SQL and run it manually to make sure it isn't some invalid SQL that is causing the error.
I have created the EF model and then in a Class I have written the following Code to retrieve the value form the DataBase. And store the value in another Table. But it gives me the Error "DATAREADER IS INCompatable" as explained Below..
EmpRole empr = new EmpRole();
empr.EmpId = strEmpId;
string str="select RoleId from RoleName where roleName like '"+strDesignation+"'";
var context= DbAccess.Data.ExecuteStoreQuery<RoleName>(str, null); //Here Showing Error
empr.RoleId = Convert.ToInt16(context);
DbAccess.Data.EmpRoles.AddObject(empr);
DbAccess.Commit();
It's showing the error like:
DataTables were:
CREATE TABLE [dbo].[RoleName](
[SNo] [int] IDENTITY(1,1) NOT NULL,
[RoleId] [smallint] NOT NULL,
[RoleName] [varchar](50) NULL,
CONSTRAINT [PK_RoleName] PRIMARY KEY CLUSTERED
(
[RoleId] ASC
)
CREATE TABLE [dbo].[EmpRoles](
[Sno] [int] IDENTITY(1,1) NOT NULL,
[EmpId] [varchar](8) NOT NULL,
[RoleId] [smallint] NOT NULL,
[ReportingToId] [varchar](8) NULL,
CONSTRAINT [PK_EmpRoles] PRIMARY KEY CLUSTERED
(
[Sno] ASC
)
The data reader is incompatible with the specified 'MyOrgDBModel.RoleName'. A member of the type, 'SNo', does not have a corresponding column in the data reader with the same name.
Please tell me the reasons what to do to execute the sqlQuery.
This is because you are not selecting the SNo column in your select query. As you are populating in RoleName and it has property SNo column should be present in data reader. If you just want the RoleId to be in query then create new type with one property RoleId and use this. Create new type like below
public class CustomRoleName
{
int RoleId { get; set; }
}
Now change your code as follow
EmpRole empr = new EmpRole();
empr.EmpId = strEmpId;
string str="select RoleId from RoleName where roleName like '"+strDesignation+"'";
foreach(CustomRoleName rn in DbAccess.Data.ExecuteStoreQuery<CustomRoleName>(str))
{
empr.RoleId = rn.RoleId ;
DbAccess.Data.EmpRoles.AddObject(empr);
DbAccess.Commit();
break;
}
I have a single entity that always duplicate a row when it needs to update:
protected static Task RegisterToDisc(Task task)
{
try
{
using (DataContext context = new DataContext())
{
//this will print an actual existing id from the db
_log.Debug(task.ID);
context.Tasks.InsertOnSubmit(task);
context.SubmitChanges();
}
}
catch(Exception e)
{
//...
}
return task;
}
When I print the id before the save, it is actually prints out an id that is really exists in the db.
this is the table:
CREATE TABLE [dbo].[TaskSet](
[ID] [int] IDENTITY(1,1) NOT NULL,
[Message] [nvarchar](max) NOT NULL,
[Result] [nvarchar](max) NOT NULL,
[Status] [int] NOT NULL,
[Priority] [int] NOT NULL,
[Name] [nvarchar](max) NOT NULL,
[DateTimeAsked] [datetime] NOT NULL,
[DateTimePerfomed] [datetime] NOT NULL,
[SessionID] [nvarchar](max) NOT NULL,
CONSTRAINT [PK_TaskSet] PRIMARY KEY CLUSTERED
(
[ID] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
Edit
The task is comming from the database already, task.ID contains a number that is exists in the database, how come Linq inserts an entity with PK that is not null and in the db already.
in java hibernate you neet to context.insertOrUpdate(task); and it will decide what to do by the primary key.
InsertOnSubmit always marks the object for insertion. if you want to update the object u need to read it from database like
var objToUpdate = context.Tasks.SingleOrDefault(x=>x.Id == Id);
objToUpdate.Property1 = "updated value";
objToUpdate.Property2 = "updated value";
//do it for all properties that need updating
context.SubmitChanges();//since the object is tracked by context it will automatically generate sql to reflect update in db