Elasticsearch null pointer when indexing parent document - c#

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.

Related

Linq Union of two queries throws null exception on string assignment

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

What is the maximum size of an object to store in a MongoDb collection using the C# Driver 2.1.1?

I use the mongoDB C# driver 2.1.1 to store and retrieve documents in a mongoDb collection. This worked well so far until one document was CORRECTLY stored but could not be read back by the driver.
I got to that conclusion using robomongo (a user interface to monitor what's inside my collection) and manipulating the object stored.
It contains a collection of elements (around 4000 sub elements) and if I remove enough of it, the document is finally retrievable again.
The line of code used is:
public Task<T> FirstOrDefaultAsync(Expression<Func<T, bool>> predicate, CancellationToken cancellationToken = default(CancellationToken))
{
return MongoQueryable.FirstOrDefaultAsync(_collection, predicate, cancellationToken);
}
Before you ask, what I first thought is that one specific element of my sub elements set had encountered some issues while being serialized/deserialized and was creating the issue. I tested by removing randomly elements of the collection, and just the number seems to be the root of the problem.
The text file size of the Json document represents around 11 Mb - I will try now to get the actual size of the object which would be more relevant.
Something else I can add is that in the mondoDb log file, there is one line that only appear when I try to select an "oversized" document :
2016-06-29T19:30:45.982+0200 I COMMAND [conn12] command MYCOLLECTIONDb.$cmd command: aggregate
{ aggregate: "XXXX", pipeline: [ { $match: { _id: "5773e0e9a1152d259c7d2e50" } }, { $limit: 1 } ]
, cursor: {} } keyUpdates:0 writeConflicts:0 numYields:0 reslen:4188200 locks:{ Global:
{ acquireCount: { r: 6 } }, MMAPV1Journal: { acquireCount:
{ r: 3 } }, Database: { acquireCount: { r: 3 } }, Collection: { acquireCount: { R: 3 } } } 109ms
(XXXX being my custom object)
So I'd like to know if you have any idea of what's causing this issue, any hint of where I should try to look, because I am running out of ideas :)
EDIT_1: That is basically the structure of my object :
[DataContract]
public class MyClass
{
[DataMember]
public string _id { get; set; }
[DataMember]
public string XmlPreference { get; set; }
[DataMember]
public string XmlMarketDates { get; set; }
[DataMember]
public IEnumerable<ClassB> Lines { get; set; }
}
[DataContract]
public class ClassB
{
[DataMember]
public string UniqueId { get; set; }
[DataMember]
public string ParentId { get; set; }
[DataMember]
public Dictionary<string, ClassC> DataMapping {get; set;}
}
and ClassC is just a container of 7 ints and 1 object properties.
Still looking for something :)
EDIT 2: I reproduced the bug only using the mongoDb C# drivers 2.1.1 release version. Here is the code :
using MongoDB.Bson;
using MongoDB.Driver.Linq;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Text;
using System.Threading.Tasks;
namespace TestingMongoDbCsharpDriver
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Debugging starting...");
try
{
MongoDB.Driver.MongoClient myClient = new MongoDB.Driver.MongoClient("mongodb://localhost:27010");
var db = myClient.GetDatabase("DocumentStoreDb");
var collection = db.GetCollection<DocumentModel>("TestOverload");
Console.WriteLine("Collection TestOverload found");
Random rand = new Random(999999999);
DocumentModel toInsert = null;
for (int lineNb = 1; lineNb < 50000; lineNb += 1000)
{
string id = rand.Next().ToString();
Console.WriteLine(string.Format("\nCreating document with id '{0}' and {1} lines...", id, lineNb));
toInsert = Funcs.Create(id, lineNb);
Console.WriteLine("Created.");
// Saving and waiting for it to finish
collection.InsertOneAsync(toInsert).Wait();
Console.WriteLine("Inserted.");
// retrieving it
var filter = new BsonDocument("_id", new BsonDocument("$eq", id));
var cursor = collection.FindAsync<DocumentModel>(filter).Result;
cursor.MoveNextAsync().Wait();
string messFilterMethod = cursor.Current.Count() == 1 ? "Retrieved" : "Not retrieved. Bug confirmed";
Console.WriteLine("With Filter: " + messFilterMethod);
var model = MongoQueryable.FirstOrDefaultAsync(collection.AsQueryable(), e => e._id == id).Result;
string mess = model != null ? "Retrieved" : "Not retrieved. Bug confirmed";
Console.WriteLine("With AsQueryable: " + mess);
// Removing it
collection.DeleteOneAsync(filter).Wait();
Console.WriteLine("Deleted.\n");
Console.ReadKey();
}
}
catch (Exception e)
{
Console.WriteLine("\n\nERROR: " + e.Message);
}
Console.WriteLine("\n\n**************** NO BUG *************\n");
}
}
public static class Funcs
{
public static DocumentModel Create(string uniqueId, int nbLines)
{
Random random = new Random(2000000);
List<MyDocumentSubElement> listOk = new List<MyDocumentSubElement>();
for (int lines = 0; lines < nbLines; ++lines)
{
Dictionary<string, SnapCellValueStyle> newDico = new Dictionary<string, SnapCellValueStyle>();
for (int i = 0; i < 10; ++i)
{
int idSnap = random.Next();
var snap = new SnapCellValueStyle()
{
alignment = idSnap,
Value = "okkkkkkkkkkzzzzkk"
};
newDico.Add("newKey_" + idSnap.ToString(), snap);
}
MyDocumentSubElement doc = new MyDocumentSubElement()
{
Icon = 516,
Name = "name du truc",
ParentId = "parent id",
type = SubElementType.T3,
UniqueId = "uniqueId_" + random.Next().ToString(),
MapColumnNameToCellValue = newDico
};
listOk.Add(doc);
}
int headerId = random.Next();
MyDocumentHeader temp = new MyDocumentHeader()
{
Comment = "comment",
Date = DateTime.Now,
ExtractionId = headerId,
Id = "id ok _ " + headerId,
Name = "Name really interesting name",
OwnerId = 95115,
RootFolioId = 51,
SnapshotViewId = MyDocumentType.Type2
};
DocumentModel toInsert = new DocumentModel()
{
_id = uniqueId,
Header = temp,
XmlMarketDates = "<xmlPrefok65464f6szf65ze4f6d2f1ergers5fvefref3e4f05e4f064z68f4xd35f8eszf40s6e40f68z4f0e8511xf340ed53f1d51zf68d4z61ef644dcdce4f64zef84zOKok>><>>",
XmlPreference = "<<zefaiunzhduiaopklzpdpakzdplapdergergfdgergekâzda4684z16ad84s2dd0486za04d68a04z8d0s1d d4az80d46az4d651s1d8 154efze40f6 4ze65f40 65ze40f6z4e>><>>>",
Lines = listOk
};
return toInsert;
}
}
// Imitation of SnapshotDocModel
[DataContract]
public class DocumentModel
{
[DataMember]
public string _id { get; set; }
[DataMember]
public MyDocumentHeader Header { get; set; }
[DataMember]
public string XmlPreference { get; set; }
[DataMember]
public string XmlMarketDates { get; set; }
[DataMember]
public IEnumerable<MyDocumentSubElement> Lines { get; set; }
}
[DataContract]
public class MyDocumentHeader
{
[DataMember]
public string Id { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public int OwnerId { get; set; }
[DataMember]
public string Comment { get; set; }
[DataMember]
public DateTime Date { get; set; }
[DataMember]
public int RootFolioId { get; set; }
[DataMember]
public MyDocumentType SnapshotViewId { get; set; }
[DataMember]
public int ExtractionId { get; set; }
}
[DataContract]
public class MyDocumentSubElement
{
[DataMember]
public string UniqueId { get; set; }
[DataMember]
public string ParentId { get; set; }
[DataMember]
public int Icon { get; set; }
[DataMember]
public SubElementType type { get; set; }
[DataMember]
public Dictionary<string, SnapCellValueStyle> MapColumnNameToCellValue { get; set; }
[DataMember]
public string Name { get; set; }
}
public class SnapCellValueStyle
{
public object Value { get; set; }
public int alignment { get; set; }
public int Red { get; set; }
public int Green { get; set; }
public int Blue { get; set; }
public int currency { get; set; }
public int decimalPoint { get; set; }
public int kind { get; set; }
public int style { get; set; }
}
#region enum
public enum MyDocumentType
{
Undefined,
Type1,
Type2,
Type3,
Type4,
Type5
}
public enum SubElementType
{
T1,
T2,
T3
}
#endregion
}
If you test it, you will see that there is the point where the AsQueryable method does not work anymore where as the document is still retrievable by the method using a filter.
Problem fixed in the version 2.2.4 of the c# mongo db driver (probably with the bug https://jira.mongodb.org/browse/CSHARP-1645)
Thanks :)

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

cannot be called with instance of type 'System.Data.Entity.Core.Objects.ObjectQuery

I want to Find Username by userId
this code snippet working
Discussion_CreateBy = db.AspNetUsers.Find(discussion.CreatedBy).UserName,
and this once not working in following controller class
Comment_CreateBy = db.AspNetUsers.Find(c.CreatedBy).UserName,
this is my model classes
public class DiscussionVM
{
public int Disussion_ID { get; set; }
public string Discussion_Title { get; set; }
public string Discussion_Description { get; set; }
public Nullable<System.DateTime> Discussion_CreateDate { get; set; }
public string Discussion_CreateBy { get; set; }
public string Comment_User { get; set; }
public IEnumerable<CommentVM> Comments { get; set; }
}
public class CommentVM
{
public int Comment_ID { get; set; }
public Nullable<System.DateTime> Comment_CreateDate { get; set; }
public string Comment_CreateBy { get; set; }
public string Comment_Description { get; set; }
}
this is whole controller class
public ActionResult Discussion_Preview()
{
int Discussion_ID = 1;
var discussion = db.AB_Discussion.Where(d => d.Discussion_ID == Discussion_ID).FirstOrDefault();
var comments = db.AB_DiscussionComments.Where(c => c.Discussion_ID == Discussion_ID);
DiscussionVM model = new DiscussionVM()
{
Disussion_ID = discussion.Discussion_ID,
Discussion_Title = discussion.Discussion_Name,
Discussion_Description = discussion.Discussion_Name,
Discussion_CreateBy = db.AspNetUsers.Find(discussion.CreatedBy).UserName,
Discussion_CreateDate = discussion.CreatedDate,
Comments = comments.Select(c => new CommentVM()
{
Comment_ID = c.Comment_ID,
Comment_Description = c.Comment_Discription,
Comment_CreateBy = db.AspNetUsers.Find(c.CreatedBy).UserName,
Comment_CreateDate = c.CreatedDate
})
};
return View(model);
}
Getting following error
Method 'Project.Models.AspNetUser Find(System.Object[])' declared on type 'System.Data.Entity.DbSet1[Project.Models.AspNetUser]' cannot be called with instance of type 'System.Data.Entity.Core.Objects.ObjectQuery1[Project.Models.AspNetUser]'
Discussion_CreateBy = db.AspNetUsers.Find(discussion.CreatedBy).UserName
Works because discussion is an in-memory object because you are executing a query by calling FirstOrDefault on it:
var discussion = db.AB_Discussion.Where(d => d.Discussion_ID == Discussion_ID).FirstOrDefault();
On the other hand in the following statement:
db.AspNetUsers.Find(c.CreatedBy).UserName
c is not queried yet because
db.AB_DiscussionComments.Where(c => c.Discussion_ID == Discussion_ID)
returns an IQueriable and not the actual collection of comments
The easiest way to fix it is to bring all your comments into memory (since you are anyway need them all) :
var comments = db.AB_DiscussionComments.Where(c => c.Discussion_ID == Discussion_ID).ToList();

Only return specific properties

I have developed my first API controlled in MVC4 and through the scaffolding I have got it to automatically output a list of items:
// GET api/ItemList
public IEnumerable<ItemOption> GetItemOptions()
{
var itemoptions = db.ItemOptions.Include(i => i.Item);
return itemoptions.AsEnumerable();
}
This shows all the item properties from my model:
public class ItemOption
{
public int ItemOptionId { get; set; }
public bool Active { get; set; }
public string Name { get; set; }
public string test1 { get; set; }
public double PriceNet { get; set; }
}
How can I specify specific fields I wish to be returned? For example, I just want the ItemOptionId, Active and Name to be returned.
I have tried adding additional includes, but this seems to be at an object level.
Try creating a new type to represent the properties you'd like to return:
public class ItemOptionResult
{
public int ItemOptionId { get; set; }
public bool Active { get; set; }
public string Name { get; set; }
}
And then projecting your ItemOption collection, like this:
// GET api/ItemList
public IEnumerable<ItemOptionResult> GetItemOptions()
{`enter code here`
var itemoptions =
db.ItemOptions
.Select(i =>
new ItemOptionResult
{
ItemOptionId = i.ItemOptionId,
Active = i.Active,
Name = i.Name
});
return itemoptions.AsEnumerable();
}
Try this :
var itemoptions = db.ItemOptions.Select(io => new ItemOption()
{
ItemOptionId = io.ItemOptionId,
Active = io.Active ,
Name = io.Name
}
return itemoptions.AsEnumerable();

Categories