Good morning. I'm trying to cut down the time on a LINQ Query. During the execution of the block of code, against large datasets it takes about 30-40 seconds to complete, which is way too long.
foreach (var patientVisitId in patientVisitIds)
{
var firstVisit = visitsWithBills.First(vb => vb.Visit.PatientVisitId == patientVisitId).Visit;
firstVisit.Bills = (from visitBill in visitsWithBills
where visitBill.Visit.PatientVisitId == patientVisitId
select visitBill.Bill).ToList();
visitTOs.Add(firstVisit);
}
I've tried replacing the == within the where statement with .contains which I read is supposed to be quicker, that almost doubles the execution time.
foreach (var patientVisitId in patientVisitIds)
{
var firstVisit = visitsWithBills.First(vb => vb.Visit.PatientVisitId == patientVisitId).Visit;
firstVisit.Bills = (from visitBill in visitsWithBills
where visitBill.Visit.PatientVisitId.Contains(patientVisitId)
select visitBill.Bill).ToList();
visitTOs.Add(firstVisit);
}
Here's the Object that firstVisit represents.
public class VisitTO
{
#region { Instance properties }
/// <summary>
/// Gets or sets the bed/room number for the visit
/// </summary>
public string Bed { get; set; }
/// <summary>
/// Gets or sets the bills for the visit
/// </summary>
public List<BillTO> Bills { get; set; }
/// <summary>
/// Gets or sets the date of admission for the visit
/// </summary>
public DateTime DateOfAdmission { get; set; }
/// <summary>
/// Gets or sets the primary diagnosis for the patient
/// </summary>
public string DX1 { get; set; }
/// <summary>
/// Gets or sets the secondary diagnosis for the patient
/// </summary>
public string DX2 { get; set; }
/// <summary>
/// Gets or sets the tertiary diagnosis for the patient
/// </summary>
public string DX3 { get; set; }
/// <summary>
/// Gets or sets the quaternary diagnosis for the patient
/// </summary>
public string DX4 { get; set; }
/// <summary>
/// Gets or sets the quinary diagnosis for the patient
/// </summary>
public string DX5 { get; set; }
/// <summary>
/// Gets or sets the senary diagnosis for the patient
/// </summary>
public string DX6 { get; set; }
/// <summary>
/// Gets or sets whether the patient has been discharged
/// </summary>
public bool IsDischarged { get; set; }
/// <summary>
/// Gets or sets the patient's full name
/// </summary>
public string PatientName { get; set; }
/// <summary>
/// Gets or sets the patient's current visit ID
/// </summary>
public string PatientVisitId { get; set; }
/// <summary>
/// Gets or sets the patient's current visit ID
/// </summary>
public string PatientId { get; set; }
/// <summary>
/// Gets or sets the name of the patient's primary care physician
/// </summary>
public string PrimaryCarePhysician { get; set; }
/// <summary>
/// Gets or sets the hosting site
/// </summary>
public string Site { get; set; }
/// <summary>
/// Gets or sets the team assignment
/// </summary>
public string Team { get; set; }
#endregion { Instance properties }
}
Here's BillTO object.
public class BillTO
{
#region { Public instance properties }
/// <summary>
/// Gets or sets the bill's date
/// </summary>
public DateTime Date { get; set; }
/// <summary>
/// Gets or sets the name for the doctor on the bill
/// </summary>
public string DoctorName { get; set; }
/// <summary>
/// Gets or sets the bill's type
/// </summary>
public string Type { get; set; }
/// <summary>
/// Gets or sets the encounter for this bill
/// </summary>
public string Encounter { get; set; }
/// <summary>
/// Gets or sets the CPT Code
/// </summary>
public string CptCode { get; set; }
#endregion { Public instance properties }
}
Database Query to the get the list.
private static readonly Func<MDataContext, IQueryable<VisitBillTO>> ActiveVisitsWithBillsQuery =
CompiledQuery.Compile<MContext, IQueryable<VisitBillTO>>(
dbContext => (
from visit in dbContext.AV
join bill in dbContext.ABills on visit.PatientVisitId equals bill.PatientVisitId
where (visit.BFlag == null || visit.BFlag != "BI")
orderby visit.PatientVisitId
select new VisitBillTO
{
Bill = new BillTO
{
Date = bill.Date.GetValueOrDefault(DateTime.Today),
DoctorName = bill.DoctorName,
Type = bill.Type,
Encounter = bill.Encounter,
CptCode = bill.CptCode
},
Visit = new VisitTO
{
Bed = visit.Bed,
DateOfAdmission = visit.DateOfAdmission.GetValueOrDefault(DateTime.Today),
DX1 = visit.DX1,
DX2 = visit.DX2,
DX3 = visit.DX3,
DX4 = visit.DX4,
DX5 = visit.DX5,
DX6 = visit.DX6,
IsDischarged = (visit.IsDischargedCode != null && visit.IsDischargedCode == "Y"),
PatientName = (visit.PatientFullName ?? visit.PatientLastName + ", " + visit.PatientFirstName),
PatientVisitId = visit.PatientVisitId,
PatientId = visit.PatientID,
PrimaryCarePhysician = visit.PrimaryCarePhysician,
Site = visit.Site,
Team = visit.Team
}
}
));
As I expected, you can do this far more efficiently in one query:
from visit in dbContext.AV
where (visit.BFlag == null || visit.BFlag != "BI")
&& patientVisitIds.Contains(visit.PatientVisitId)
orderby visit.PatientVisitId
select new VisitBillTO
{
Bed = visit.Bed,
...
Team = visit.Team,
Bills = (from bill
in visit.Bills
select new BillTO
{
Date = bill.Date.GetValueOrDefault(DateTime.Today),
DoctorName = bill.DoctorName,
Type = bill.Type,
Encounter = bill.Encounter,
CptCode = bill.CptCode
})
}
Now the database does all the heavy lifting of combining the objects. Everything is shaped as you want in one go.
Note that I assume the navigation property visit.Bills to exist. These properties normally exist in LINQ-to-SQL contexts, but in the designer for some reason they're always collapsed by default, so people tend to overlook them. If for some reason the property isn't there you can replace...
Bills = (from bill in visit.Bills
by...
Bills = (dbContext.ABills where visit.PatientVisitId == bill.PatientVisitId
Related
The name '' does not exist in the current context
crn
courseid
timedays
Roomnumber
At the display, none of the items are recognized. Why is the display not seeing them when they were declared as set and gets?
using System;
using System.Collections.Generic;
using System.Text;
public class Section
{
private int crn;
private String courseId;
private String timeDays;
private String roomNumber;
private int instructor;
/// <summary>
/// Creates a new instance of a section
/// </summary>
/// <param name="crn"></param>
/// <param name="courseId"></param>
/// <param name="timeDays"></param>
/// <param name="roomNumber"></param>
/// <param name="instructor"></param>
public Section(int crn, string courseId, string timeDays, string roomNumber, int instructor)
:this(crn, courseId, timeDays, roomNumber, instructor, "")
{
}
/// <summary>
/// Creates a new instance of a section
/// </summary>
/// <param name="crn"></param>
/// <param name="courseId"></param>
/// <param name="timeDays"></param>
/// <param name="roomNumber"></param>
/// <param name="instructor"></param>
/// <param name="message"></param>
public Section(int crn, string courseId, string timeDays, string roomNumber, int instructor, string message)
{
this.Crn = crn;
this.CourseId = courseId;
this.TimeDays = timeDays;
this.RoomNumber = roomNumber;
this.Instructor = instructor;
this.Message = message;
}
/// <summary>
/// Gets or sets the crn
/// </summary>
public int Crn { get; set; }
/// <summary>
/// gets or sets the course id
/// </summary>
public string CourseId { get; set; }
/// <summary>
/// gets or sets the time days
/// </summary>
public string TimeDays { get; set; }
/// <summary>
/// gets or sets the room number
/// </summary>
public string RoomNumber { get; set; }
/// <summary>
/// Gets or sets the instructor
/// </summary>
public int Instructor { get; set; }
/// <summary>
/// Gets or sets the message
/// </summary>
public string Message { get; set; }
public void display(){
System.Console.WriteLine("CRN = "+ getCrn());
System.Console.WriteLine("CourseID = "+ getCourseId());
System.Console.WriteLine("Time Days = " + getTimeDays());
System.Console.WriteLine("Room Number = " + getRoomNumber());
}
}
I think display() needs to look like below. I don't know how your display() function is even compiling.
public void display()
{
System.Console.WriteLine("CRN = "+ Crn);
System.Console.WriteLine("CourseID = "+ CourseId);
System.Console.WriteLine("Time Days = " + TimeDays);
System.Console.WriteLine("Room Number = " + RoomNmber);
}
In addition, since you have all your properties declared with { get; set; }, you don't need any backing member variables (the compiler automatically takes care of these for you). So you can delete the lines that look like this:
private int crn;
private String courseId;
private String timeDays;
private String roomNumber;
private int instructor;
This should work and it's very basic. My json string is (from the debugger):
json "{\"companyId\":0,\"companyName\":\"Windward 3\",\"apiKey\":null,\"isEnabled\":false,\"isActive\":false,\"accruedRtusThisMonth\":0,\"billedRtusThisMonth\":0,\"overageChargesThisMonth\":0.0,\"pricingMode\":3,\"discount\":null,\"billingMode\":1,\"maxAdditionalMonthlyCharge\":123.0,\"billing\":{\"personId\":0,\"companyId\":0,\"isActive\":false,\"isAdmin\":false,\"isBilling\":false,\"firstName\":\"David\",\"lastName\":\"Thielen\",\"address1\":\"1 Main St.\",\"address2\":null,\"city\":\"Boulder\",\"state\":\"CO\",\"country\":\"USA\",\"postalCode\":\"80301\",\"phone\":\"123-456-7890\",\"email\":\"david#windward.net\",\"password\":\"tree\"},\"creditCard\":{\"cardNumber\":\"4111111111111111\",\"expiration\":\"2015-02-18T23:37:01.3135786Z\",\"cvv\":\"123\",\"useCardPerson\":false,\"cardPerson\":null},\"nextBaseBillingDate\":\"0001-01-01T00:00:00\",\"nextOverageBillingDate\":\"0001-01-01T00:00:00\",\"billingStatus\":0,\"billingErrorDate\":null,\"deactivateDate\":null,\"deleteDate\":null}" string
My code is as follows:
CompanyWrapper companyWrapper = JsonConvert.DeserializeObject<CompanyWrapper>(json,
new JsonSerializerSettings());
And the CompanyWrapper class is:
public class CompanyWrapper
{
/// <summary>
/// For the JSON population.
/// </summary>
public CompanyWrapper()
{
}
/// <summary>
/// For unit tests
/// </summary>
public CompanyWrapper(string companyName, PricingPlan.PRICING_MODE pricingMode, Company.BILLING_MODE billingMode, decimal maxAdditionalMonthlyCharge, PersonWrapper billing, CreditCardWrapper creditCard)
{
this.companyName = companyName;
this.pricingMode = pricingMode;
this.billingMode = billingMode;
this.maxAdditionalMonthlyCharge = maxAdditionalMonthlyCharge;
this.billing = billing;
this.creditCard = creditCard;
}
/// <summary>
/// The primary key. This is auto-generated in the database.
/// </summary>
public int companyId { get; private set; }
/// <summary>
/// The company name. This cannot be changed.
/// </summary>
public string companyName { get; private set; }
...
}
On return companyWrapper.companyName == null. That should be assigned. What am I missing?
thanks - dave
You need to make the property setters public.
I have call a list of phone records in wcf service. Now i need to add comments & feedback against all records, in such a way that user clicks the notes button and then enter the comments and feedback aaisnt a specific record.
Here is my class FOR notes
public class CallNote
{
public int Id { get; set; }
///<Summary>
///
///</Summary>
public string Comments { get; set; }
///<Summary>
///
///</Summary>
///
public string FeedBack { get; set; }
///<Summary>
///
///</Summary>
///
public string Login { get; set; }
}
Class for callhistory
public class CallHistory
{
/// <summary>
///
/// </summary>
///
public int CallId { get; set; }
/// <summary>
///
/// </summary>
///
public string Login { get; set; }
/// <summary>
///
/// </summary>
public string FirstName { get; set; }
/// <summary>
///
/// </summary>
public string LastName { get; set; }
/// <summary>
///
/// </summary>
public string Email { get; set; }
/// <summary>
///
/// </summary>
public string Country { get; set; }
/// <summary>
///
/// </summary>
public string Phone { get; set; }
/// <summary>
///
/// </summary>
public string DialedNumber { get; set; }
/// <summary>
///
/// </summary>
public string CallStart { get; set; }
/// <summary>
///
/// </summary>
public string CallEnd { get; set; }
/// <summary>
///
/// </summary>
public string TariffDescription { get; set; }
/// <summary>
///
/// </summary>
}
and here is my controller
public ActionResult CreateNote()
{
var result = Manager.GetUsersWhoHaveConsumedFreeCredit();
JavaScriptSerializer serializer = new JavaScriptSerializer();
var callHistory = serializer.Deserialize<List<CallHistory>>(result);
return View(callHistory.ToPagedList(1, Settings.PagingSize));
}
[HttpPost]
public ActionResult CreateNote(CallNote callnote)
{
CallNote_Db db = new CallNote_Db();
if (ModelState.IsValid)
{
db.callnote.Add(callnote);
db.SaveChanges();
return RedirectToAction("CallHistory");
}
return PartialView("CallHistory", callnote);
}
public ActionResult UsersWhoHaveConsumedFreeCredit(int Id = 1)
{
var result = Manager.GetUsersWhoHaveConsumedFreeCredit(); ;
JavaScriptSerializer serializer = new JavaScriptSerializer();
var callHistory = serializer.Deserialize<List<CallHistory>>(result);
CallNote callNote = new Models.CallNote();
CallHistoryFilter callHistoryFilter = new Models.CallHistoryFilter();
MyYelloAdminEntities db = new Models.MyYelloAdminEntities();
{
callHistoryFilter.Countries = db.Countries.ToList();
callHistoryFilter.Countries.Insert(0, new Country { Title = "All", Prefix = "-1" });
var model = new UsersWhoHaveConsumedFreeCredit
{
CallHistory = callHistory.ToPagedList(Id, Settings.PagingSize),
CallHistoryFilter = callHistoryFilter
};
return View(model);
}
}
How i can add comments against each record.
If you want to combine two different WCF data contracts for your UI/display convenience,
then you can create a view model in your MVC project that is composed of these two datacontracts.
And once after you fetch WCF contracts to your MVC app then crate a datamapper(perhaps by using Automapper or a mapper of your choice) between WCF to your ViewModel and reverse the process while pushing data from UI back to WCF service.
Update based on your comments:
Please take a look at AutoMapper, it is a mapping tool to copy your property data from one type of entity to other type based on the mapping strategy you defined.
If you need to maintain comments/feedback at the currently logged in user then, you can track that on server and you need to only get the new comments from UI to controller and prepare the Model to save accordingly.
If you need to maintain comments/feedback at the respective user(the registered user who is providing the comments/feedback against your content) level, then you can maintain a hidden field on view and then you should post the userid and comments back to controller and save them.
I'm trying to create a new post in my site, but for some reason, EF throws the following error:
A relationship from the 'PostAttributeValue_Definition' AssociationSet
is in the 'Deleted' state. Given multiplicity constraints, a
corresponding 'PostAttributeValue_Definition_Source' must also in the
'Deleted' state.
Since I'm not trying to delete anything and I didn't changed or removed any value, I'm confused why I'm getting this error.
My db context contains the following:
modelBuilder.Entity<PostAttributeValue>().HasRequired<PostAttributeDefinition>(a => a.Definition).WithOptional().Map(m =>
{
m.MapKey("RelatedAttributeDefinitionId");
}).WillCascadeOnDelete(false);
/* Category(required) to PostAttributeDefinition(many) */
modelBuilder.Entity<PostAttributeDefinition>().HasRequired<Category>(a => a.OwnerCategory).WithMany(c => c.AttributeDefinitions).Map(m =>
{
m.MapKey("OwnerCategoryId");
}).WillCascadeOnDelete(true);
My publish method looks like this:
//
// POST: /Post/Publish/5
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Publish(int? id, PublishViewModel model)
{
if (!id.HasValue || id.Value < 1)
{
return HttpNotFound();
}
var category = this.categoryService.Find(id.Value);
if (category == null)
{
return HttpNotFound();
}
if (ModelState.IsValid)
{
List<PostAttributeValue> attributes = new List<PostAttributeValue>();
foreach (var attribute in model.Attributes)
{
attributes.Add(new PostAttributeValue()
{
Definition = attribute.Definition,
RawValue = attribute.Value.Serialize()
});
}
Post post = new Post()
{
Title = model.Title,
Description = model.Description,
City = model.City.City,
Brokerage = model.Brokerage,
Location = model.Location,
RequestedPrice = model.Price.Value,
ParentCategory = category,
Attributes = attributes,
};
this.postService.PublishPost(post);
return RedirectToAction("ImageSelection", new { id = post.PostIdentifier });
}
return View(model);
}
The error is been thrown from the Repository class Add() method, which looks like this:
public TEntity Add(TEntity entity)
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
try
{
var result = this.Entity.Add(entity);
this.context.SaveChanges();
return result;
}
catch
{
var deletedEntries = context.ChangeTracker.Entries().Where(e => e.State != EntityState.Added && e.State != EntityState.Unchanged);
throw;
}
}
Because the exception related to entities in deleted state, I've wrote this linq query that checks for entities that're not unchanged or added, but it returns zero results... I really
don't know why I'm getting this error.
Just to note, I'm using proxy entities, and from inspection in the debugger everything seems OK - the entire values are been filled in as excepted.
Hope somebody can help me figure it out. Thanks! :)
Edited:
The PostAttributeDefinition model class, which is a class that describes a custom attribute definition (each category can have different custom attributes - for example, "TV Shows" can have a custom attribute "Number of episodes" while Movies "IMDB rank", for example)
public class PostAttributeDefinition
{
#region Members
private Lazy<object> lazyDataValue = null;
private Lazy<PostAttributeDefinitionValidationRules> lazyValidatorValue = null;
private Type cachedDataType;
#endregion
/// <summary>
/// The filter name
/// </summary>
[Key]
public int DefinitionId { get; set; }
/// <summary>
/// The owner category
/// </summary>
[Required]
public virtual Category OwnerCategory { get; set; }
/// <summary>
/// The filter title
/// </summary>
[Required]
public string Title { get; set; }
/// <summary>
/// Metadata enum that provides extra data about the data type
/// </summary>
public PostAttributeTypeMetadata TypeMetadata { get; set; }
/// <summary>
/// Bitwise metadata that provides data about the object in display mode
/// </summary>
public PostAttributeDisplayModeMetadata DisplayModeMetadata { get; set; }
public PostAttributeEditorType EditorType { get; set; }
/// <summary>
/// The attribute raw default value
/// </summary>
[Required]
public byte[] RawDataValue { get; set; }
/// <summary>
/// The attribute raw associated validation attributes
/// </summary>
/// <remarks>
/// This field is used only by EF.
/// YES - It's against DDD rules, and I need to seperate it. setting it in TODO.
/// </remarks>
public byte[] RawValidationRules { get; set; }
/// <summary>
/// Is this field required
/// </summary>
/// <remarks>
/// This field does not relate to the validation rules since we should check it
/// only in creation / modification of the post and not in search for example.
/// </remarks>
public bool IsRequired { get; set; }
/// <summary>
/// The attribute validators
/// </summary>
public PostAttributeDefinitionValidationRules ValidationRules
{
get
{
if (lazyValidatorValue == null)
{
lazyValidatorValue = new Lazy<PostAttributeDefinitionValidationRules>(() =>
{
if (this.RawValidationRules == null || this.RawValidationRules.Length == 0)
{
return new PostAttributeDefinitionValidationRules();
}
return this.RawValidationRules.Deserialize() as PostAttributeDefinitionValidationRules;
});
}
return lazyValidatorValue.Value;
}
set
{
this.RawValidationRules = value.Serialize();
this.lazyValidatorValue = null;
}
}
/// <summary>
/// Get the stored object data type
/// </summary>
public Type ValueDataType
{
get
{
// Make sure we've loaded the serialized value
if (lazyDataValue == null)
{
RetriveDataValue();
}
return cachedDataType;
}
}
#region Value content
/// <summary>
/// Store the attribute default value
/// </summary>
/// <typeparam name="TType">The default value type</typeparam>
/// <param name="value">The default value</param>
/// <returns>Fluent style writing - returning the same object</returns>
public PostAttributeDefinition StoreDataValue<TType>(TType value)
{
// In case of empty value, we need to defaultize it
if (value == null)
{
value = value.DefaultizeNullableValueForSerialize<TType>();
}
// Store as bytes
RawDataValue = value.Serialize<TType>();
// Reset the lazy cached value
lazyDataValue = null;
// Fluent style returned value
return this;
}
/// <summary>
/// Retrive the item default value
/// </summary>
/// <typeparam name="TType">The item default value data type</typeparam>
/// <returns>The item default value</returns>
/// <exception cref="InvalidOperationException">Thrown in case the raw value is null or empty.</exception>
public TType RetriveDataValue<TType>()
{
return (TType)RetriveDataValue();
}
/// <summary>
/// Retrive the item default value
/// </summary>
/// <returns>The item default value</returns>
/// <exception cref="InvalidOperationException">Thrown in case the raw value is null or empty.</exception>
public object RetriveDataValue()
{
// Make sure that we've loaded the lazy value
if (lazyDataValue == null)
{
lazyDataValue = new Lazy<object>(() =>
{
// Deserialize
var value = RawDataValue.Deserialize();
// Remve defaultize in case we've done that (by the way, we're caching the type
// in order to retrive it in case of null value)
value = value.ReverseDefaultizeNullableValueForDeSerialize(out cachedDataType);
// Return it
return value;
});
}
// Return the cached lazy data value
return lazyDataValue.Value;
}
#endregion
}
The PostAttributeValue class, which I wish to save and causes the problems is:
public class PostAttributeValue
{
/// <summary>
/// The attribute value id
/// </summary>
[Key]
public int AttributeValueId { get; set; }
/// <summary>
/// The value owner post
/// </summary>
public virtual Post OwnerPost { get; set; }
/// <summary>
/// The value attribute definition id
/// </summary>
//public int RelatedAttributeDefinitionId { get; set; }
/// <summary>
/// The value attribute definition
/// </summary>
public virtual PostAttributeDefinition Definition { get; set; }
/// <summary>
/// The stored raw value
/// </summary>
public byte[] RawValue { get; set; }
#region Value content
/// <summary>
/// Check if there's anything stored in the raw value
/// </summary>
/// <returns>Boolean value indicates if there's anything stored in the raw value</returns>
public bool HasValue()
{
return RawValue != null;
}
/// <summary>
/// Retrive the item value
/// </summary>
/// <typeparam name="TType">The item default value data type</typeparam>
/// <returns>The item value</returns>
/// <exception cref="InvalidOperationException">Thrown in case the raw value is null or empty.</exception>
public TType RetriveValue<TType>()
{
return (TType)RetriveValue();
}
/// <summary>
/// Retrive the item value
/// </summary>
/// <returns>The item value</returns>
/// <exception cref="InvalidOperationException">Thrown in case the raw value is null or empty.</exception>
public object RetriveValue()
{
if (RawValue == null)
{
throw new InvalidOperationException("Could not deserialize the value since there's nothing in the raw value.");
}
return RawValue.Deserialize();
}
#endregion
}
Note that I'm using a ViewModel for the attributes (model.Attributes is an IEnumerable)
public class PostAttributeViewModel
{
[ReadOnly(true)]
[Editable(false)]
public PostAttributeDefinition Definition { get; set; }
[Required]
public int DefinitionId { get; set; }
[Required]
public string DefinitionVertificationToken { get; set; }
public object Value { get; set; }
}
The Definition attribute, that I'm assigning and mapping to the PostAttributeValue model is auto-filled by EF.
I am creating an ICriteria query for this equivalent sql query.
SELECT fCustomerID,
ISNULL(
(SELECT SUM(payinv.fAmount) AS Expr1
FROM dbo.tARPayment AS pay
INNER JOIN dbo.tARPaymentInvoice AS payinv ON pay.fPaymentID = payinv.fPaymentID
INNER JOIN dbo.tARInvoice AS inv ON payinv.fInvoiceID = inv.fARInvoiceID
WHERE (pay.fIsPosted = CASE pay.fPaymentType WHEN 'CM' THEN 0 WHEN 'EPD' THEN 0 ELSE 1 END)
AND (inv.fCustomerID <> dbo.tARCustomer.fCustomerID)
AND (pay.fCustomerID = dbo.tARCustomer.fCustomerID)), 0)
FROM dbo.tARCustomer
GROUP BY fCustomerID
But I am not getting anyway that how can I generate equivalent nhibernate ICriteria query.
This is payment class
public partial class tARPayment
{
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="tARPayment"/> class.
/// </summary>
public tARPayment()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="tARPayment"/> class.
/// </summary>
/// <param name="fPaymentID">The fPaymentID of guid type.</param>
public tARPayment(System.Guid fPaymentID)
{
this.ID = fPaymentID;
}
#endregion
#region Properties
/// <summary>
/// Gets or sets payment id.
/// </summary>
public virtual System.Guid fPaymentID { get; set; }
/// <summary>
/// Gets or sets fCustomerID.
/// </summary>
public virtual System.Guid fCustomerID { get; set; }
/// <summary>
/// Gets or sets check number.
/// </summary>
public virtual string fCheckNumber { get; set; }
/// <summary>
/// Gets or sets amount.
/// </summary>
public virtual decimal fAmount { get; set; }
/// <summary>
/// Gets or sets customer detail.
/// </summary>
public virtual tARCustomer Customer { get; set; }
public virtual IList<tARPaymentInvoice> PaymentInvoices { get; set; }
#endregion
#region Methods
/// <summary>
/// partial class for payment.
/// </summary>
/// <returns>The method get code.</returns>
public override int GetHashCode()
{
return ID.GetHashCode();
}
#endregion
}
This is a invoice class
public partial class tARInvoice
{
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="tARInvoice"/> class.
/// </summary>
public tARInvoice()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="tARInvoice"/> class.
/// </summary>
/// <param name="fARInvoiceID">The fARInvoiceID.</param>
public tARInvoice(System.Guid fARInvoiceID)
{
this.ID = fARInvoiceID;
}
#endregion
#region Properties
/// <summary>
/// Gets or sets fARInvoiceID.
/// </summary>
public virtual Guid fARInvoiceID { get; set; }
/// <summary>
/// Gets or sets fCustomerID.
/// </summary>
public virtual Guid fCustomerID { get; set; }
/// <summary>
/// Gets or sets Delivery Method.
/// </summary>
public virtual string fDeliveryMethod { get; set; }
/// <summary>
/// Gets or sets Invoice Number.
/// </summary>
public virtual int? fARInvoiceNumber { get; set; }
public virtual tARCustomer Customer { get; set; }
public virtual IList<tARPaymentInvoice> PaymentInvoices { get; set; }
#endregion
#region Methods
/// <summary>
/// retrieve Hash Code.
/// </summary>
/// <returns>The method get code.</returns>
public override int GetHashCode()
{
return ID.GetHashCode();
}
#endregion
}
This is a payment invoice class.
public partial class tARPaymentInvoice
{
#region Constructor
/// <summary>
/// Initializes a new instance of the <see cref="tARPaymentInvoice"/> class.
/// </summary>
public tARPaymentInvoice()
{
}
/// <summary>
/// Initializes a new instance of the <see cref="tARPaymentInvoice"/> class.
/// </summary>
/// <param name="fPaymentInvoiceID">The Invoice ID.</param>
public tARPaymentInvoice(System.Guid fPaymentInvoiceID)
{
this.ID = fPaymentInvoiceID;
}
#endregion
#region Properties
/// <summary>
/// Gets or sets fPaymentInvoiceID.
/// </summary>
public virtual System.Guid fPaymentInvoiceID { get; set; }
/// <summary>
/// Gets or sets fPaymentID.
/// </summary>
public virtual System.Guid fPaymentID { get; set; }
/// <summary>
/// Gets or sets fInvoiceID.
/// </summary>
public virtual System.Guid fInvoiceID { get; set; }
/// <summary>
/// Gets or sets tARPayment.
/// </summary>
public virtual tARPayment Payment { get; set; }
/// <summary>
/// Gets or sets tARInvoice.
/// </summary>
public virtual tARInvoice Invoice { get; set; }
#endregion
#region Methods
/// <summary>
/// get hash codes.
/// </summary>
/// <returns>The hash code.</returns>
public override int GetHashCode()
{
return ID.GetHashCode();
}
#endregion
}
Rather than converting the above query to LINQ or HQL, I would recommend making the query into a view, and then using NHibernate to query that view.
SQL
CREATE VIEW vCustomerAmount AS
SELECT fCustomerID,
ISNULL(
(SELECT SUM(payinv.fAmount) AS Expr1
FROM dbo.tARPayment AS pay
INNER JOIN dbo.tARPaymentInvoice AS payinv ON pay.fPaymentID = payinv.fPaymentID
INNER JOIN dbo.tARInvoice AS inv ON payinv.fInvoiceID = inv.fARInvoiceID
WHERE (pay.fIsPosted = CASE pay.fPaymentType WHEN 'CM' THEN 0 WHEN 'EPD' THEN 0 ELSE 1 END)
AND (inv.fCustomerID <> dbo.tARCustomer.fCustomerID)
AND (pay.fCustomerID = dbo.tARCustomer.fCustomerID)), 0) [Amount]
FROM dbo.tARCustomer
GROUP BY fCustomerID
C# DTO
public class CustomerAmount
{
public int fCustomerID { get; set; }
public decimal Amount { get; set; }
}
Query
List<CustomerAmount> customerAmounts = session.Query<CustomerAmount>().ToList();
Not sure about nHibernate, but does this rewritten query help get the same answer and is something you can run with easier?
SELECT T.fCustomerID,
coalesce( SUM( payinv.fAmount ), 0 ) as SumAmt
FROM
dbo.tARCustomer T
JOIN dbo.tARPayment AS pay
ON T.fCustomerID = pay.fCustomerID
AND pay.fIsPosted = CASE pay.fPaymentType
WHEN 'CM' THEN 0
WHEN 'EPD' THEN 0
ELSE 1 END
JOIN dbo.tARPaymentInvoice AS payinv
ON pay.fPaymentID = payinv.fPaymentID
INNER JOIN dbo.tARInvoice AS inv
ON payinv.fInvoiceID = inv.fARInvoiceID
AND inv.fCustomerID <> T.fCustomerID
GROUP BY
T.fCustomerID