Linq Union of two queries throws null exception on string assignment - c#

I have these two queries where the first one returns organization with departments and the second one returns organizations without departments and after that I use Union() for my final query since I want to display in table both results.
Union() requires to have fulfilled exactly the same properties in both queries so I had to assign "Empty" Department object in second query, but I need to have my Department Name empty and it throws me null exception and I have no idea why it should even throw it, it doesnt make sense to me.
When I tried to assign for example organization.Name into Department.Name suddently it didnt throw me null exception at all.
Is there any possibility to assign empty string into Department name?
var query1 = UserAccountOwnSuppliers
.Where(organization => organization.IsBuyer)
.SelectMany(organization => organization.Departments
.Select(department =>
new UserAccountMarketsForSupplierDTO
{
Organization = new OrganizationBaseDTO
{
Id = organization.Id,
Name = organization.Name,
RegionId = organization.RegionId,
CreatorDepartmentId = organization.CreatorDepartmentId,
CreatorOrganizationId = organization.CreatorOrganizationId,
CreatorId = organization.CreatorId,
},
Department = new DepartmentBaseDTO
{
Id = department.Id,
Name = department.Name
}
})).OrderBy(dto => dto.Organization.Name);
var query2 = UserAccountOwnSuppliers
.Where(organization => organization.IsBuyer)
.Select(organization => new UserAccountMarketsForSupplierDTO
{
Organization = new OrganizationBaseDTO
{
Id = organization.Id,
Name = organization.Name,
RegionId = organization.RegionId,
CreatorDepartmentId = organization.CreatorDepartmentId,
CreatorOrganizationId = organization.CreatorOrganizationId,
CreatorId = organization.CreatorId,
},
Department = new DepartmentBaseDTO
{
Id = 0,
//here it throws null exception when I try to assign some value
Name = "---"
}
}).OrderBy(dto => dto.Organization.Name); ;
var query = query2.Union(query1);
return query.OrderBy(dto => dto.Organization.Name);
DTOs
public class DepartmentBaseDTO : IEntity<int>
{
public string Name { get; set; }
public int Id { get; set; }
}
public class OrganizationBaseDTO : IEntity<int>
{
public string Name { get; set; }
public int? ParentOrganizationId { get; set; }
public int? RegionId { get; set; }
public int CreatorId { get; set; }
public int CreatorOrganizationId { get; set; }
public int CreatorDepartmentId { get; set; }
public string Code { get; set; }
}
public class UserAccountMarketsForSupplierDTO : IEntity<int>
{
public OrganizationBaseDTO Organization { get; set; } = new OrganizationBaseDTO();
public DepartmentBaseDTO Department { get; set; } = new DepartmentBaseDTO();
}
StackTrace
https://pastebin.com/j81yBYYU

Related

Elasticsearch null pointer when indexing parent document

I am attempting to set up a parent-child relationship in Elasticsearch, and I am consistently getting a null pointer exception from the server when trying to index the parent.
I am using Elasticsearch and NEST both at version 6.2.
I've basically been following this guide from the documentation: https://www.elastic.co/guide/en/elasticsearch/client/net-api/current/parent-child-relationships.html
Objects: (ESDocument is the base class, ESVendor is the parent, and ESLocation is the child)
[ElasticsearchType(Name = "Doc", IdProperty = "Id")]
public abstract class ESDocument
{
public int Id { get; set; }
public JoinField MyJoinField { get; set; }
}
[ElasticsearchType(Name = "Vendor", IdProperty = "ConsigneeID")]
public class ESVendor: ESDocument
{
public int VendorID { get; set; }
public int VendorTypeID { get; set; }
public int ClientID { get; set; }
public int CompanyID { get; private set; }
public int LocationID { get; set; }
public bool Active { get; set; }
public TimeSpan? OpenTime { get; set; }
public TimeSpan? CloseTime { get; set; }
public bool AppointmentRequired { get; set; }
public decimal? Latitude { get; set; }
public decimal? Longitude { get; set; }
public bool PositionRequested { get; set; }
public bool PositionFailed { get; set; }
public int? NoteID { get; set; }
public int? OldID { get; set; }
public ESVendor(Vendor vendor)
{
if (vendor == null)
{
return;
}
Id = vendor.VendorID;
CompanyID = vendor.CompanyID;
Active = vendor.Active;
VendorID = vendor.VendorID;
Latitude = vendor.Latitude;
Longitude = vendor.Longitude;
VendorTypeID = vendor.VendorTypeID;
ClientID = vendor.ClientID;
LocationID = vendor.LocationID;
Latitude = vendor.Latitude;
OpenTime = vendor.OpenTime;
CloseTime = vendor.CloseTime;
AppointmentRequired = vendor.AppointmentRequired;
PositionRequested = vendor.PositionRequested;
PositionFailed = vendor.PositionFailed;
NoteID = vendor.NoteID;
OldID = vendor.OldID;
}
public ESVendor()
{
}
}
[ElasticsearchType(Name = "Location", IdProperty = "LocationID")]
public class ESLocation: ESDocument
{
public int LocationID { get; set; }
public int CompanyID { get; private set; }
public string Name { get; set; }
public string Address { get; set; }
public string Address2 { get; set; }
public string CityStateZipCountry { get; set; }
public string Note { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Zip { get; set; }
public string Country { get; set; }
public ESLocation(Location location)
{
if (location == null)
{
return;
}
Id = location.LocationID;
CompanyID = location.CompanyID;
Address = location.Address;
Address2 = location.Address2;
LocationID = location.LocationID;
Name = location.Name;
Note = location.Note;
City = location.City;
State = location.State;
Zip = location.Zip;
Country = location.Country;
CityStateZipCountry = location.Country + " " + location.State + " " + location.Zip + " " + location.Country;
}
public ESLocation()
{
}
}
Mapping + Indexing:
StaticConnectionPool connectionPool = new StaticConnectionPool(_nodes);
ConnectionSettings connectionSettings = new ConnectionSettings(connectionPool, sourceSerializer: SourceSerializer)
.DisableDirectStreaming()
.DefaultMappingFor<ESDocument>(m => m.IndexName("vendors").TypeName("doc"))
.DefaultMappingFor<ESVendor>(m => m.IndexName("vendors").TypeName("doc").RelationName("Vendor_Location"))
.DefaultMappingFor<ESLocation>(m => m.IndexName("vendors").TypeName("doc"));
ElasticClient esClient = new ElasticClient(connectionSettings);
IExistsResponse existsResponse = await esClient.IndexExistsAsync(new IndexExistsRequest(Indices.Parse("vendors")));
if (!existsResponse.Exists)
{
esClient.CreateIndex("vendors", c => c
.Index<ESVendor>()
.Mappings(ms => ms
.Map<ESVendor>(m => m
.RoutingField(r => r.Required())
.AutoMap<ESVendor>()
.AutoMap<ESLocation>()
.Properties(props => props
.Join(j => j
.Name(p => p.MyJoinField)
.Relations(r => r
.Join<ESVendor, ESLocation>()
)
)
)
)
));
}
using (Entities dbContext = new Entities())
{
foreach (Vendor vendor in dbContext.Vendors)
{
if (!(await esClient.DocumentExistsAsync(new DocumentExistsRequest("vendors", typeof (Vendor), vendor.VendorID))).Exists)
{
ESVendor parent = new ESVendor(vendor)
{
MyJoinField = JoinField.Root<ESVendor>()
};
var result = esClient.IndexDocument<ESDocument>(parent);
ESLocation child = new ESLocation(vendor.Location)
{
MyJoinField = JoinField.Link<ESLocation, ESVendor>(parent)
};
result = esClient.IndexDocument<ESDocument>(child);
}
}
}
It is consistently returning the below error every time it attempts to index the parent document.
Invalid NEST response built from a unsuccessful low level call on POST: /vendors/doc
# Audit trail of this API call:
- [1] BadResponse: Node: http://192.168.50.240:9200/ Took: 00:00:00.2060485
# OriginalException: Elasticsearch.Net.ElasticsearchClientException: The remote server returned an error: (500) Internal Server Error.. Call: Status code 500 from: POST /vendors/doc. ServerError: Type: null_pointer_exception Reason: "id must not be null" ---> System.Net.WebException: The remote server returned an error: (500) Internal Server Error.
at System.Net.HttpWebRequest.GetResponse()
at Elasticsearch.Net.HttpConnection.Request[TResponse](RequestData requestData)
--- End of inner exception stack trace ---
# Request:
{"vendorID":1,"vendorTypeID":1,"clientID":349,"companyID":1,"locationID":4994,"active":true,"openTime":null,"closeTime":null,"appointmentRequired":false,"latitude":null,"longitude":null,"positionRequested":false,"positionFailed":false,"noteID":null,"oldID":1626,"id":1,"myJoinField":"Vendor_Location"}
# Response:
{"error":{"root_cause":[{"type":"null_pointer_exception","reason":"id must not be null"}],"type":"null_pointer_exception","reason":"id must not be null"},"status":500}
I've been fighting this for days now when it should have been a 30 minute task, I'm at my wits end.
Thank you in advance, your assistance is very much appreciated!
The problem is the attribute applied to EsVendor
[ElasticsearchType(Name = "Vendor", IdProperty = "ConsigneeID")]
public class ESVendor: ESDocument
{
// ...
}
The IdProperty tells NEST to infer the id for EsVendor types from the ConsigneeID property, but looking at the model provided, there is no property with that name. It looks like you don't need to specify this property in the attribute, and instead can rely on IdProperty in the ElasticsearchTypeAttribute applied to ESDocument, which will infer the Id from the Id property.
So, removing IdProperty from the attribute applied to EsVendor
[ElasticsearchType(Name = "Vendor")]
public class ESVendor : ESDocument
{
// ...
}
will now send an index request similar to (other properties skipped for brevity) for an EsVendor
PUT http://localhost:9200/vendors/doc/1?routing=1
{
"id": 1,
"vendorID": 1,
"myJoinField": "Vendor_Location"
}
We might also want to lean on the compiler too, for string values that reference properties, and use nameof(Id)
[ElasticsearchType(Name = "Doc", IdProperty = nameof(Id))]
public abstract class ESDocument
{
public int Id { get; set; }
public JoinField MyJoinField { get; set; }
}
We can in fact remove IdProperty altogether if we want, as using the Id property to infer an ID for the document is default NEST behaviour. Going further, because the types have a DefaultMappingFor<T> on ConnectionSettings, we can remove the ElasticsearchType attributes altogether, since the default mappings on connection settings will take precedence.

Cannot initialize type with a collection initializer because it does not implement 'System.Collections.IEnumerable'

I have 3 entities for main menus. and sub menus. I created menu view model.
My Entities:
MainMenu.cs:
public UstMenuler()
{
AltMenuler = new HashSet<AltMenuler>();
}
public int ID { get; set; }
public string Name { get; set; }
public bool AktifMi { get; set; }
public int YetkiID { get; set; }
public string ControllerName { get; set; }
public string ActionName { get; set; }
public virtual Yetkilendirme Yetkilendirme { get; set; }
public virtual ICollection<AltMenuler> AltMenuler { get; set; }
SubMenu.cs:
public partial class AltMenuler
{
public AltMenuler()
{
UstMenuler = new HashSet<UstMenuler>();
}
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int ID { get; set; }
public int? YetkiID { get; set; }
public string Name { get; set; }
public string ActionName { get; set; }
public string ControllerName { get; set; }
public virtual Yetkilendirme Yetkilendirme { get; set; }
}
MyViewModel:
public class MenuViewModel
{
public UstMenuler UstMenuler { get; set; }
public AltMenuler AltMenuler { get; set; }
}
My Controller:
dbContext = new MarkettingDbContext();
int sessionYetkiID = (int)Session["yetkiID"];
MenuViewModel menuler = new MenuViewModel();
var query = (from menu in dbContext.UstMenuler
where (menu.YetkiID == sessionYetkiID)
select new MenuViewModel
{
menuler.UstMenuler.ID = menu.ID,
menuler.UstMenuler.Name = menu.Name,
menuler.UstMenuler.YetkiID = menu.YetkiID,
menuler.UstMenuler.ControllerName = menu.ControllerName,
menuler.UstMenuler.ActionName = menu.ActionName
}).ToList();
I am getting error when I execute my query. For example my sessionID is 1, I want to take my main and submenus.
The problem is your object initializer:
select new MenuViewModel
{
menuler.UstMenuler.ID = menu.ID,
menuler.UstMenuler.Name = menu.Name,
menuler.UstMenuler.YetkiID = menu.YetkiID,
menuler.UstMenuler.ControllerName = menu.ControllerName,
menuler.UstMenuler.ActionName = menu.ActionName
}
Firstly you're using menuler in the object initializer, and I'm not sure why. Next, you're trying to assign to subproperties, which even if it did compile, would result in a NullReferenceException. Collectively, that's basically not what you want to do :)
Instead, I'd use one of the two options below.
If you're happy to just copy the UstMenuler reference from the menu parameter into the new view model instance, you can do that really easily:
select new MenuViewModel { UseMenuler = menu }
Or if you want to create a new UstMenuler and copy properties from menu:
select new MenuViewModel
{
UstMenuler = new UstMenuler
{
ID = menu.ID,
Name = menu.Name,
YetkiID = menu.YetkiID,
ControllerName = menu.ControllerName,
ActionName = menu.ActionName
}
}
Either way, you don't need your menuler variable which you appear not to be using anywhere else.
As it sounds like you're using LINQ to Entities, it sounds like you may want to separate the database query part from the projection part. The simplest way to do that in your case is to avoid the query expression syntax, so you can call AsEnumerable easily. So for example:
var query = dbContext.UstMenuler
.Where(menu => menu.YetkiID == sessionYetkiID)
.AsEnumerable() // Do the projection in-process
.Select(menu => new MenuViewModel
{
UstMenuler = new UstMenuler
{
ID = menu.ID,
Name = menu.Name,
YetkiID = menu.YetkiID,
ControllerName = menu.ControllerName,
ActionName = menu.ActionName
}
})
.ToList();

How to populate my base Customer with EF

see my class structure first.
public class CustomerBase
{
public int CustomerID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string Phone { get; set; }
public string Fax { get; set; }
}
public class Customer : CustomerBase
{
public virtual List<Addresses> Addresses { get; set; }
}
public class Addresses
{
[Key]
public int AddressID { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public bool IsDefault { get; set; }
public virtual List<Contacts> Contacts { get; set; }
public int CustomerID { get; set; }
public virtual Customer Customer { get; set; }
}
public class Contacts
{
[Key]
public int ContactID { get; set; }
public string Phone { get; set; }
public string Fax { get; set; }
public bool IsDefault { get; set; }
public int AddressID { get; set; }
public virtual Addresses Customer { get; set; }
}
public class TestDBContext : DbContext
{
public TestDBContext()
: base("name=TestDBContext")
{
}
public DbSet<Customer> Customer { get; set; }
public DbSet<Addresses> Addresses { get; set; }
public DbSet<Contacts> Contacts { get; set; }
}
now this way i am trying to populate my customer base but getting error.
var bsCustomer1 = (from c in db.Customer
where (c.CustomerID == 2)
select new
{
CustomerID = c.CustomerID,
FirstName = c.FirstName,
LastName = c.LastName,
Addresses = (from ad in c.Addresses
where (ad.IsDefault == true)
from cts in ad.Contacts
where (cts != null && cts.IsDefault == true)
select ad).ToList(),
}).ToList()
.Select(x => new CustomerBase
{
CustomerID = x.CustomerID,
FirstName = x.FirstName,
LastName = x.LastName,
Address1 = x.Addresses.Select(a => a.Address1).SingleOrDefault(),
Address2 = x.Addresses.Select(a => a.Address2).SingleOrDefault(),
Phone = x.Addresses.Select(c => c.Contacts.Select(cd => cd.Phone).SingleOrDefault()),
Fax = x.Addresses.Select(c => c.Contacts.Select(cd => cd.Fax).SingleOrDefault())
}).ToList();
as per my situation a single customer may have multiple address but there should be one default one which i am pulling. a single address may have multiple contacts details but there should be one default one which i am pulling.
address1,address2, Phone and Fax are in base customer class. i want to pull single data from address and contacts tables based on isdefault is true and populate my customer. i am not very good in linq. so not being able to compose the query. please help me to compose it. thanks
Try the code below, guess it may fit about your request.
var bsCustomer1 = db.Customer.Where(p => p.CustomerID == 2)
.Select(x => new CustomerBase
{
CustomerID = x.CustomerID,
FirstName = x.FirstName,
LastName = x.LastName,
Address1 = x.Addresses.First(a => a.IsDefault).Address1,
Address2 = x.Addresses.First(a => a.IsDefault).Address2,
Phone = x.Addresses.First(a => a.IsDefault).Contacts.First(c => c.IsDefault).Phone),
Fax = x.Addresses.First(a => a.IsDefault).Contacts.First(c => c.IsDefault).Fax)
}).ToList();
Without knowing your actual meaning when you say: "i want to pull single data from address and contacts tables based on isdefault is true and populate my customer" that could mean two things:
I want to project a new object
I want to UPDATE the backing database.
Okay a few things about EF:
You have a context for CRUD (Create, Retrieve, Update, Delete) statements to the database.
The Context knows all the objects you identified in the database when setting up the EF file.
The t4 templates are created for entity context and the entity name itself and generate the context reference in the previous steps as well as create POCO class objects.
To create NEW objects you don't have to reference the object above it or below it. You just need to create it and then update the database with it.
So for an example of EF let's say I have two database tables:
I have a table tePerson that has fields: PersonId, FirstName, LastName, OrderId. This table has values
1 Brett X 1
2 Emily X 2
4 Ryan Y 1
10 Mark Z 1
OrderId is a foreign Key to a table teOrder with only has two fields: OrderId and Description.
1 Shirt
2 Dress
And my POCO objects generated from the T4 are:
public partial class tePerson
{
public int PersonId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public Nullable<int> OrderId { get; set; }
public virtual teOrder teOrder { get; set; }
}
It is important to note that that 'virtual teOrder' points to another POCO for me like this:
public partial class teOrder
{
public teOrder()
{
this.tePersons = new HashSet<tePerson>();
}
public int OrderId { get; set; }
public string Description { get; set; }
public virtual ICollection<tePerson> tePersons { get; set; }
}
Example for just projecting and for updating the database from the context as well as updating the database below. The key thing to remember is that objects when doing 'selects' with EF are not realized till you do a method like 'ToList()' to make them concrete. Else they are context db set which you cannot chain off of.
public class OtherPerson
{
public int PersonId { get; set; }
public string PersonLongName { get; set; }
public teOrder Order { get; set; }
}
static void Main(string[] args)
{
using (var context = new TesterEntities())
{
//Say I just want to project a new object with a select starting from orders and then traversing up. Not too hard
var newObjects = context.teOrders.Where(order => order.OrderId == 1)
//SelectMan will FLATTEN a list off of a parent or child in a one to many relationship
.SelectMany(peopleInOrderOne => peopleInOrderOne.tePersons)
.ToList()
.Select(existingPerson => new OtherPerson
{
PersonId = existingPerson.PersonId,
PersonLongName = $"{existingPerson.FirstName} {existingPerson.LastName}",
Order = existingPerson.teOrder
})
.ToList();
newObjects.ForEach(newPerson => Console.WriteLine($"{newPerson.PersonId} {newPerson.PersonLongName} {newPerson.Order.Description}"));
// Just an action clause to repeat find items in my context, the important thing to note is that y extends teOrder which is another POCO inside my POCO
Action<string, List<tePerson>> GetOrdersForPeople = (header, people) =>
{
Console.WriteLine(header);
people.ForEach(person => Console.WriteLine($"{person.FirstName} {person.LastName} {person.teOrder.Description}"));
Console.WriteLine();
};
//I want to look at a person and their orders. I don't have to do multiple selects down, lazy loading by default gives me a child object off of EF
GetOrdersForPeople("First Run", context.tePersons.ToList());
//Say I want a new order for a set of persons in my list?
var newOrder = new teOrder { Description = "Shoes" };
context.teOrders.Add(newOrder);
context.SaveChanges();
//Now I want to add the new order
context.tePersons.SingleOrDefault(person => person.PersonId == 1).teOrder = newOrder;
context.SaveChanges();
//I want to rexamine now
GetOrdersForPeople("After changes", context.tePersons.ToList());
//My newOrder is in memory and I can alter it like clay still and the database will know if I change the context
newOrder.Description = "Athletic Shoes";
context.SaveChanges();
GetOrdersForPeople("After changes 2", context.tePersons.ToList());
//Say I want to update a few people with new orders at the same time
var peopleBesidesFirst = context.tePersons.Where(person => person.PersonId != 1).ToList();
var firstPersonInList = context.tePersons.Where(person => person.PersonId == 1).ToList();
var newOrders = new List<teOrder> {
new teOrder { Description = "Hat", tePersons = peopleBesidesFirst },
new teOrder { Description = "Tie", tePersons = firstPersonInList }
};
context.teOrders.AddRange(newOrders);
context.SaveChanges();
GetOrdersForPeople("After changes 3", context.tePersons.ToList());
}
Console.ReadLine();
}

Unable to create a constant value of type 'AddressModel'. Only primitive types or enumeration types are supported in this context

In the EF query below, any time an child contact address field is assigned to the Address property of the TaxReceiptsWithChargesModel, I get the error message:
"Cannot create constant value of type 'AddressModel'"
If I comment out the line that assigns the address, then the error does not occur. What could the issue be?
Edit: Typically, the causes of this problem I've seen elsewhere have to do with using the contains or equals LINQ methods, but the cause of this particular issue seems to lie elsewhere.
Here are the relevant sections of code:
//GetChildContactAddress
var childContactAddress = lgcCcpModel.ChildContacts
.Where(cc => cc.UUID == ltrm.ChildContactId)
.Select(cc => new AddressModel()
{
Address1 = cc.Address.STREET,
City = cc.Address.CITY,
Province = cc.Address.PROVINCE,
PostalCode = cc.Address.POSTALCODE
}).FirstOrDefault();
//Create the Tax Receipt Model with the Charge List
return unitOfWork.LegacyTaxReceiptStore.GetQuery()
.Where(ltr => ltr.LegacyTaxReceiptId == ltrm.LegacyTaxReceiptId)
.Select(c => new TaxReceiptsWithChargesModel()
{
LegacyTaxReceiptId = ltrm.LegacyTaxReceiptId,
ChildContactId = ltrm.ChildContactId,
ChildContact = ltrm.ChildContact,
EmailAddress = ltrm.EmailAddress,
ChildId = ltrm.ChildId,
ChildName = ltrm.ChildName,
ChargesTotal = ltrm.ChargesTotal,
TaxReceiptAmount = ltrm.TaxReceiptAmount.Value,
TaxReceiptYear = ltrm.TaxReceiptYear,
Address = childContactAddress,
ReceiptNumber = $"{ltrm.TaxReceiptYear}-{ltrm.LegacyTaxReceiptId.ToString().PadLeft(6, '0')}",
Charges = taxReceiptChargesModelList,
}).FirstOrDefault();
public class TaxReceiptsWithChargesModel : ITaxReceiptsModel
{
public int LegacyTaxReceiptId { get; set; }
public string ChildContactId { get; set; }
public string ChildContact { get; set; }
public string EmailAddress { get; set; }
public IAddressModel Address { get; set; }
public decimal? OpeningBalance { get; set; }
public decimal? InvoicesTotal { get; set; }
public decimal? PaymentsTotal { get; set; }
public string ChildId { get; set; }
public string ChildName { get; set; }
public decimal? ChargesTotal { get; set; }
public decimal? TaxReceiptAmount { get; set; }
public string State { get; set; }
public int TaxReceiptYear { get; set; }
public string ReceiptNumber { get; set; }
public int? BinaryDocumentId { get; set; }
public List<TaxReceiptsChargesModel> Charges { get; set; }
}
public interface IAddressModel
{
string Address1 { get; set; }
string Address2 { get; set; }
string City { get; set; }
string Country { get; set; }
string PostalCode { get; set; }
string Province { get; set; }
}
That is because childContactAddress object (and also taxReceiptChargesModelList) is already in memory and when you try to assign a complex object in the projection of your second query, the Linq provider can't translated that object to SQL. One option can be call AsEnumerable extension method:
return unitOfWork.LegacyTaxReceiptStore.GetQuery()
.Where(ltr => ltr.LegacyTaxReceiptId ==ltrm.LegacyTaxReceiptId)
.AsEnumerable()
.Select(c => new TaxReceiptsWithChargesModel()
{
LegacyTaxReceiptId = ltrm.LegacyTaxReceiptId,
ChildContactId = ltrm.ChildContactId,
ChildContact = ltrm.ChildContact,
EmailAddress = ltrm.EmailAddress,
ChildId = ltrm.ChildId,
ChildName = ltrm.ChildName,
ChargesTotal = ltrm.ChargesTotal,
TaxReceiptAmount = ltrm.TaxReceiptAmount.Value,
TaxReceiptYear = ltrm.TaxReceiptYear,
Address = childContactAddress,
ReceiptNumber = $"{ltrm.TaxReceiptYear}-{ltrm.LegacyTaxReceiptId.ToString().PadLeft(6, '0')}",
Charges = taxReceiptChargesModelList,
}).FirstOrDefault();
Update
Your issue can be also solve this way:
var result=unitOfWork.LegacyTaxReceiptStore.GetQuery()
.FirstOrDefault(ltr => ltr.LegacyTaxReceiptId ==ltrm.LegacyTaxReceiptId);
return new TaxReceiptsWithChargesModel()
{
LegacyTaxReceiptId = result.LegacyTaxReceiptId,
ChildContactId = result.ChildContactId,
ChildContact = result.ChildContact,
EmailAddress = result.EmailAddress,
ChildId = result.ChildId,
ChildName = result.ChildName,
ChargesTotal = result.ChargesTotal,
TaxReceiptAmount = result.TaxReceiptAmount.Value,
TaxReceiptYear = result.TaxReceiptYear,
Address = childContactAddress,
ReceiptNumber = $"{result.TaxReceiptYear}-{result.LegacyTaxReceiptId.ToString().PadLeft(6, '0')}",
Charges = taxReceiptChargesModelList,
};
You have to apply [Serializable()] decorator however you cannot do it to interfaces.
Instead, implement your custom interface with ISerializable {}
A similar question has been answered below, credit of this post goes to Oded.
Why are interfaces not [Serializable]?
Cheers
Can you please tell what is point of using interfaces as a model property.
Microsoft do not encourage use of in interfaces as a model property. You can restrict changes in your property by using getter and setter methods .
See this post
https://stackoverflow.com/a/8455558/2173098

How to write LINQ query on Generic List

I have a situation where I have a generic method which accepts an object of type generic and I want to write a LINQ query on that object.
Here is an example:
Generic Method:
public static void GetNonNonVerifiedPersons<TResult>(Person<TResult> model)
{
// How To Write LINQ Here to get non verified person
}
Student Class:
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsVerified { get; set; }
}
Teacher Class:
public class Teacher
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsVerified { get; set; }
}
Person Class:
public class Person<T>
{
public List<T> PersonList { get; set; }
}
Main Class:
// 1. Get Non Verified Students
var persons = new Person<Student>();
var students = new List<Student>()
{
new Student { Id = 1, Name = "Student_A", IsVerified = true },
new Student { Id = 2, Name = "Student_B", IsVerified = false },
};
persons.PersonList = new List<Student>();
persons.PersonList.AddRange(students);
GetNonNonVerifiedPersons(persons);
// 2. Get Non Verified Teachers
var persons2 = new Person<Teacher>();
var teachers = new List<Teacher>()
{
new Teacher { Id = 1, Name = "Teacher_A", IsVerified = true },
new Teacher { Id = 2, Name = "Teacher_B", IsVerified = false },
new Teacher { Id = 3, Name = "Teacher_C", IsVerified = false },
};
persons2.PersonList = new List<Teacher>();
persons2.PersonList.AddRange(teachers);
GetNonNonVerifiedPersons(persons2);
You should use interface to be able to specify the type of Teacher and Student in generic type. When you use where clause compiler is able to do the type checks at compile time.
public interface IHuman
{
string Name { get; set; }
bool IsVerified { get; set; }
}
public class Teacher : IHuman
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsVerified { get; set; }
}
public class Student : IHuman
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsVerified { get; set; }
}
And then your method should be like this. Here we have where clause that says only accept generic type TResult when implements IHuman.
public static IEnumerable<TResult> GetNonNonVerifiedPersons<TResult>(Person<TResult> model) where TResult : IHuman
{
return model.PersonList.Where(x => !x.IsVerified);
}
Update : I highly suggest you to make the big changes because its how it should be.
Other way which is not common and extremely slow is to check for the types at runtime.
public static IEnumerable<TResult> GetNonNonVerifiedPersons<TResult>(Person<TResult> model)
{
var list = model.PersonList;
var t = list.FirstOrDefault() as Teacher;
if (t != null)
{
return model.PersonList.Where(x => !(x as Teacher).IsVerified);
}
var s = list.FirstOrDefault() as Student;
if (s != null)
{
return model.PersonList.Where(x => !(s as Student).IsVerified);
}
return null;
}
May be this can do the trick:
IList<Person<TResult>> xyz = new List<Person<TResult>>();
var list = xyz.Where(a => a.GetType() == typeof(Student).IsVerified);
I didn't check it in IDE but something like this would work

Categories