Dynamic selecting of children records - c#

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 );

Related

EF DefaultIfEmpty where statement

I have three tables and I am trying to get the Customer Response. This Customer has not Answer the question so in the MeetingPollingResponseValues CustomerId is null as well as MeetingPollingPartsValuesId. But I need to have that where (mppss.MeetingPollingPartsId == MeetingPollingPartsId && mppvs.CustomerId == CustomerId) for when Customer has data in that table. I have a the DefaultIfEmpty so I not sure if I need to add or to the where statement?
DB Tables
CREATE TABLE [dbo].[MeetingPollingParts](
[MeetingPollingPartsId] [int] IDENTITY(1,1) NOT NULL,
[MeetingPollingQuestionId] [int] NULL,
[MeetingPollingPartsTypeId] [int] NULL
)
CREATE TABLE [dbo].[MeetingPollingPartsValues](
[MeetingPollingPartsValuesId] [int] IDENTITY(1,1) NOT NULL,
[QuestionValue] [nvarchar](max) NULL,
[MeetingPollingPartsValuesTypeId] [int] NULL,
[MeetingPollingPartsId] [int] NULL
)
CREATE TABLE [dbo].[MeetingPollingResponseValues](
[MeetingPollingResponseValuesId] [int] IDENTITY(1,1) NOT NULL,
[MeetingPollingPartsValuesId] [int] NULL,
[CustomerId] [int] NULL
)
DB
QuestionValue| MeetingPollingPartsId| MeetingPollingPartsValuesId| CustomerId
--------------------------------------------------------------------------------
Yes | 588 | NULL | NULL
No | 588 | NULL | NULL
EF
var MeetingPollingParticipantsAnswers = (from mppss in db.MeetingPollingParts
join mppv in db.MeetingPollingPartsValues on mppss.MeetingPollingPartsId equals mppv.MeetingPollingPartsId
join mppvs in db.MeetingPollingResponseValues on mppv.MeetingPollingPartsValuesId equals mppvs.MeetingPollingPartsValuesId into actualAnswers
from mppvs in actualAnswers.DefaultIfEmpty()
where (mppss.MeetingPollingPartsId == MeetingPollingPartsId && mppvs.CustomerId == CustomerId)
select new Model.MeetingPollingParticipantsAnswers
{
Question = mppv.QuestionValue,
Selected = aa.MeetingPollingPartsValuesId == aa.MeetingPollingPartsValuesId ? true : false,
MeetingPollingPartsValuesId = aa.MeetingPollingPartsValuesId
}).ToList();

Replacing a paramater in SQL for a foreign key

SELECT
StaffID,
SUM(Treatment.TreatmentPrice) AS TotalStaffRevenue,
SUM(Treatment.TreatmentPrice) * ? AS Commission
FROM
Treatment
INNER JOIN
Appointment ON Appointment.TreatmentID = Treatment.TreatmentID
WHERE
AppointmentDate >= '2018/05/11'
AND AppointmentDate <= '2018/05/12'
GROUP BY
staffid WITH ROLLUP
CREATE TABLE Staff (
StaffID int IDENTITY NOT NULL,
Forename varchar(20) NOT NULL,
Surname varchar(20) NOT NULL,
MobileNumber varchar(11) NOT NULL,
EmailAddress varchar(20) NULL,
PostCode varchar(8) NULL,
HouseNumber varchar(4) NULL,
Commission decimal(6,2) NOT NULL,
PRIMARY KEY(StaffID)
);
GO
CREATE TABLE Treatment (
TreatmentID int identity NOT NULL,
TreatmentName varchar(20) NOT NULL,
TreatmentPrice money NOT NULL,
CategoryID int NOT NULL,
TreatmentDescription varchar(40) NOT NULL,
PRIMARY KEY(TreatmentID, CategoryID)
);
GO
CREATE TABLE Appointment (
AppointmentID int IDENTITY NOT NULL,
StaffID int NOT NULL,
TreatmentID int NOT NULL,
CustomerID int NOT NULL,
AppointmentDate date NOT NULL,
AppointmentTime time(0) NOT NULL,
PRIMARY KEY (AppointmentID, StaffID, CustomerID, TreatmentID)
);
I want the ability to multiply the sum of TreatmentPrice by Staff.Commission. I have tried INNER JOINing with Staff but it still doesn't work also how would I implement this in the front end (c#) would i use a for each loop, this would then populate a datagrid.
How did you get Staff.Commission without any join to the Staff table in your query?
Try
SELECT
Staff.StaffID,
SUM(Treatment.TreatmentPrice) AS TotalStaffRevenue,
SUM(Treatment.TreatmentPrice)*Commission AS Commission
FROM
Treatment
INNER JOIN
Appointment ON Appointment.TreatmentID = Treatment.TreatmentID
inner join Staff on Appointment.StaffID=Staff.StaffID
WHERE
AppointmentDate >= '2018/05/11'
AND AppointmentDate <= '2018/05/12'
GROUP BY
Staff.StaffID,Commission WITH ROLLUP

Map SQL to class in Dapper

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;
});

Order by child records using dynamic field with entity framework

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.

The DataReader Is Incompatible

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;
}

Categories