ASP.NET Entity Framework property not loaded while ID filled - c#

This is something that worked up to now and now it just, stopped working (I know, weird, there's probably some silly mistake..)
I have a TripsVM, which contains a list of trips. I load these in my service, returning a List<>.
The problem occurs when I iterate over the trips collection and try to get trip.TripCategory.Name, as the TripCategory is empty, even though TripCategoryID has a value.
This all happens at the backend, I load the trips and then try to iterate over them, they are not being send from the page.
I could probably just load the trip by trip itself, but it used to work and this bug just came up after months of usage.
Any suggestions of where to look for bugs would be really appreciated.
Thanks
Error:
Exception Details: System.NullReferenceException: Object reference not set to an instance of an object.
Where error occurs:
foreach (Trip trip in tripsVM.TripsList) {
var a = trip.TripCategory.Name;
TripsVM:
private List<Trip> _TripsList;
public List<Trip> TripsList
{
get
{
if (_TripsList == null)
{
_TripsList = TripsService.GetTrips();
if (_TripsList == null)
_TripsList = new List<Trip>();
}
return _TripsList;
}
set { _TripsList = value; }
}
Service:
public static List<Trip> GetTrips()
{
return DB.Trips.Where(...).OrderBy(...).ToList();
}
Trip class:
public partial class Trip
{
public int TripID { get; set; }
public int TripCategoryID { get; set; }
....
public virtual TripCategory TripCategory { get; set; }
}

Its looks like your DB context disposed before foreach code or LazyLoadingEnabled set to false in context.
In Service add using
using System.Data.Entity;
And modify loading method
public static List<Trip> GetTrips()
{ return DB.Trips.Where(...).Include(t=>t.TripCategory).OrderBy(...).ToList(); }

I think your code looks fine but you should add some if statements to avoid null exception, because you are returning something with where clause, so you might end up with empty query result and empty list, and in that list you are trying to reach an element of a list object:
if(tripsVM.TripsList != null){
foreach (Trip trip in tripsVM.TripsList) {
var a = trip.TripCategory.Name;
}
}
else
{
// handle empty list
}
private List<Trip> _TripsList;
public List<Trip> TripsList
{
get
{
_TripsList = new List<Trip>();
if(TripsService.GetTrips() != null)
{
_TripsList.add(TripsService.GetTrips());
}
return _TripsList;
}
set { _TripsList = value; }
}

Related

c# GroupPrincipal.FindByIdentity finds the group, but when using GetMembers getting error - there is no such object on the server

this code used to work fine for the past year,
now it is still working, but i have only 4 groups that generate this error...
the code is simple:
using (var context = new PrincipalContext(ContextType.Domain, domName))
{
foreach (string grp in myGroups)
{
using (var group = GroupPrincipal.FindByIdentity(context, IdentityType.Name, grp))
{
PrincipalSearchResult<Principal> usersList;
usersList = group.GetMembers(true);
int usersListCount = usersList.Count();
}}}
when these specific groups come to search , i get the group and can see its description in the group object variable, but when getting its members i get an error massage :
base: "There is no such object on the server.\r\n"
ErrorCode: -2147016656
again,this happens only with 4 specific groups from the same domain, and same OU.
this just started a few days ago without me changing anything, not permissions, nothing in the code, very strange...
any ideas ?
When I encountered this problem I could not have an empty group. I had to produce "best possible" results while the network people were working to resolve the "foreign SID" issue.
I know it is a lot extra but it satisfied the auditors so maybe it will help you. This is what I did:
Precursor: I had already built a class that held all the properties of the AD Entity.
Got a list of users and all their group memberships.
Wrapped the call to get members in a try... catch and when this error occurred I inserted a "Group Membership" property of "Error Retrieving members"
When I had iterated through all the Groups I grabbed a list of all groups that had the error message as a group member then queried the Users list to get a list of all the users who were members of that group.
Then inserted Property records with the found users names.
Since this answer is more about solution structure I will only give a very brief outline of the classes used. While far from elegant it gave me a reusable container that was easy to understand and share and provided a solution that was durable across several networks. It probably lacks in many ways but it passes test #1 - it worked.
public class ADPropEntry : IComparable<ADPropEntry>
{
#region Properties
public string Name { get { return _name; } set { _adName = value; SetPropVals(_adName); } }
public string Value { get { return _v; } set { _v = value; DoValConversion(); } }
public bool IsVisible { get { return _isVis; } set { _isVis = value; } }
public string ConvertTo { get { return _convertVal; } set { _convertVal = value; } }
public int ID { get { return _id; } set { _id = value; } }
#endregion
private void SetPropVals(string s)
{
switch (s)
{
case "accountexpires": _name = "Account Expires"; _isVis = false; _convertVal = "FromFileTime"; break;
... more handles each property conversion
}
}
}
public class ADEntity : IComparable<ADEntity>
{
#region Properties
public string Name { get { return _name; } set { _name = value; } }
public List<ADPropEntry> MyProperty { get { return _ade; } set { _ade = value; } }
public string EntityType { get { return _entT; } set { _entT = value; } }
public string ADName { get { return GetProperty("SAM Account Name"); } }
#endregion
}
This formed provided me a durable data container and then I used another class to query AD in whatever method makes sense. This was packaged in a DLL that the client application could use.
class ADAccess
{
#region Properties
public bool HasErrors { get { return (bool)(_errMsg.Length > 10); } }
public string ErrorMsg { get { return _errMsg; } }
public List<ADEntity> GroupEntries { get { return _lstGrps; } }
public List<ADEntity> UserEntries { get { return _lstUsrs; } }
public List<ADEntity> PrinterEntries { get { return _lstPrts; } }
public List<ADEntity> ComputerEntries { get { return _lstCmps; } }
#endregion
public List<ADEntity> GetADListByMSO(string groupType)
{
if (groupType == "")
{
// get them all return an empty list populating properties
}
else
{
// set the context and fetch return populated list
}
}
Used the same structure to report on SQL server permissions as well.
i found out the issue,
the problematic groups contained users from different domains,
once removed these users from the groups , everything went back to work.
thanks.

List Filtering performance issue in wpf C# Viewmodel

I came across a performance issues when doing normal list filtering using FirstOrDefault. I am getting the data from the server in <2ms but the filtering takes 15,252 ms.This looks strange to me and I will be glad if someone could help me on this.
Here is the method and this line Loginaccess = loginlist.FirstOrDefault(x => x.LogName == LogTitle); takes 15,252 ms to execute.
private void GetData()
{
LoginServices obj = new LoginServices();
loginlist = obj.getlogins();
Loginaccess = loginlist.FirstOrDefault(x => x.LogName == LogTitle);
}
Here is how the list and Entity type is declared
public List<LoginEntity> loginlist
{
get;
set;
}
private LoginEntity _loginaccess;
public LoginEntity Loginaccess
{
get { return _loginaccess; }
set
{
_loginaccess = value;
}
}

MongoDB Concurrent writing/fetching from multiple processes causes bulk write operation error

I'm currently implementing a MongoDB database for caching.
I've made a very generic client, with the save method working like this:
public virtual void SaveAndOverwriteExistingCollection<T>(string collectionKey, T[] data)
{
if (data == null || !data.Any())
return;
var collection = Connector.MongoDatabase.GetCollection<T>(collectionKey.ToString());
var filter = new FilterDefinitionBuilder<T>().Empty;
var operations = new List<WriteModel<T>>
{
new DeleteManyModel<T>(filter),
};
operations.AddRange(data.Select(t => new InsertOneModel<T>(t)));
try
{
collection.BulkWrite(operations, new BulkWriteOptions { IsOrdered = true});
}
catch (MongoBulkWriteException mongoBulkWriteException)
{
throw mongoBulkWriteException;
}
}
With our other clients, calling this method looking similar to this:
public Person[] Get(bool bypassCache = false)
{
Person[] people = null;
if (!bypassCache)
people = base.Get<Person>(DefaultCollectionKeys.People.CreateCollectionKey());
if (people.SafeAny())
return people;
people = Client<IPeopleService>.Invoke(s => s.Get());
base.SaveAndOverwriteExistingCollection(DefaultCollectionKeys.People.CreateCollectionKey(), people);
return people;
}
After we've persisted data to the backend we reload the cache from MongoDB by calling our Get methods, passing the argument true. So we reload all of the data.
This works fine for most use cases. But considering how we are using a Web-garden solution (multiple processes) for the same application this leads to concurrency issues. If I save and reload the cache while another user is reloading the page, sometimes it throws a E11000 duplicate key error collection.
Command createIndexes failed: E11000 duplicate key error collection:
cache.Person index: Id_1_Name_1_Email_1 dup
key: { : 1, : "John Doe", : "foo#bar.com" }.
Considering how this is a web garden with multiple IIS processes running, locking won't do much good. Considering how bulkwrites should be threadsafe I'm a bit puzzled. I've looked into Upserting the data, but changing our clients to be type specific and updating each field will take too long and feels like unnecessary work. Therefore I'm looking for a very generic solution.
UPDATE
Removed the Insert and Delete. Changed it to a collection of ReplaceOneModel. Currently experiencing issues with only the last element in a collection being persisted.
public virtual void SaveAndOverwriteExistingCollection<T>(string collectionKey, T[] data)
{
if (data == null || !data.Any())
return;
var collection = Connector.MongoDatabase.GetCollection<T>(collectionKey.ToString());
var filter = new FilterDefinitionBuilder<T>().Empty;
var operations = new List<WriteModel<T>>();
operations.AddRange(data.Select(t => new ReplaceOneModel<T>(filter, t) { IsUpsert = true }));
try
{
collection.BulkWrite(operations, new BulkWriteOptions { IsOrdered = true });
}
catch (MongoBulkWriteException mongoBulkWriteException)
{
throw mongoBulkWriteException;
}
}
Just passed in a collection of 811 items and only the last one can be found in the collection after this method has been executed.
Example of a DTO being persisted:
public class TranslationSetting
{
[BsonId(IdGenerator = typeof(GuidGenerator))]
public object ObjectId { get; set; }
public string LanguageCode { get; set; }
public string SettingKey { get; set; }
public string Text { get; set; }
}
With this index:
string TranslationSettings()
{
var indexBuilder = new IndexKeysDefinitionBuilder<TranslationSetting>()
.Ascending(_ => _.SettingKey)
.Ascending(_ => _.LanguageCode);
return MongoDBClient.CreateIndex(DefaultCollectionKeys.TranslationSettings, indexBuilder);
}

Save detached object graph using Entity Framework code first causes Primary Key violation

I'm trying to save an object graph of POCOs I have mapped to EF6 using Code First fluent notations.
Upon saving the object graph however, I stumble upon primary key violation exceptions.
The object graph is quite simple:
One Issue can contain multiple WorkItems with each one Author (as User).
The objects are populated externally (using a Web API)
When I attempt to save an issue with two workitems which refer to the same author, I would expect the issue to be inserted, the workitems to be inserted and one author to be inserted, and the other one to be referenced or be updated.
What happens however is that the issue is inserted, the workitems are inserted and both references to the same user are inserted, resulting in a primary key violation.
Simplified Issue object:
public class Issue
{
public Issue()
{
WorkItems = new List<WorkItem>();
}
public string Id { get; set; }
private List<WorkItem> _workItems;
public List<WorkItem> WorkItems
{
get { return _workItems ?? new List<WorkItem>(); }
set { _workItems = value; }
}
}
Simplified WorkItem:
public class WorkItem
{
public string Id { get; set; }
public string AuthorLogin
{
get; set;
}
private WorkItemAuthor _author;
public WorkItemAuthor Author
{
get { return _author; }
set { _author = value;
if (value != null)
{
AuthorLogin = value.Login;
}
else
{
AuthorLogin = string.Empty;
}
}
}
}
Simplified user object:
public class User
{
public string Login { get; set; }
public string FullName { get; set; }
}
Their Code-first configurations:
internal IssueConfiguration()
{
HasKey(x => x.Id);
HasMany(x => x.WorkItems);
}
internal WorkItemConfiguration()
{
HasKey(x => x.Id);
HasRequired(p => p.Author)
.WithMany(b => b.WorkItems)
.HasForeignKey(x=>x.AuthorLogin);
}
internal UsersConfiguration()
{
HasKey(x => x.Login);
}
All quite straightforward. Upon database create, de tables look fine and dandy too, with FKs on the columns where one would expect them
Now when saving the issue, it would have been nice if the object graph would be inserted, and the reference to existing objects would be recognized automagically and optionally inserted or referenced only.
I attempt to add issues accordingly:
using (var db = new Cache.Context())
{
if (db.Issues.Any(e => e.Id == issue.Id))
{
db.Issues.Attach(issue);
db.Entry(issue).State = EntityState.Modified;
}
else
{
db.Issues.Add(issue);
}
db.SaveChanges();
}
Is the solution to this issue that I walk through the object graph to manually add or attach the other objects in the graph too? I would expect by defining the proper Foreign Key values these references would be recognized.
I finally ended up doing something similar to this, quite laborious and I would still like to find a better way.
Finding out whether an entity is already attached or exists in the database turned out to be pollute the model too much (implementing IEquatable<T> is fine, but I think implementing IEntityWithKey on my POCOs pollutes the POCO too much. (and till that did not seem to suffice tracking entities in the context)
internal static void Save(this List<Issue> issues)
{
using (var db = new Context())
{
foreach (var issue in issues.ToList())
{
foreach (var workItem in issue.WorkItems.ToList())
{
if (workItem.Author != null)
{
var existing = db.Users.SingleOrDefault(e => e.Login == workItem.Author.Login);
if (existing == null)
{
db.Users.Add(workItem.Author);
}
else
{
//Update existing entities' properties
existing.Url = workItem.Author.Url;
//Replace reference
workItem.Author = existing;
}
db.SaveChanges();
}
var existingWorkItem = db.WorkItems.SingleOrDefault(e => e.Id == workItem.Id);
if (existingWorkItem == null)
{
db.WorkItems.Add(workItem);
}
else
{
//Update existing entities' properties
existingWorkItem.Duration = workItem.Duration;
//Replace reference
issue.WorkItems.Remove(workItem);
issue.WorkItems.Add(existingWorkItem);
}
db.SaveChanges();
}
var existingIssue = db.Issues.SingleOrDefault(x => x.Id == issue.Id);
if (existingIssue == null)
{
db.Issues.Add(issue);
}
else
{
//Update existing entities' properties
existingIssue.SpentTime = issue.SpentTime;
}
db.SaveChanges();
}
}
}
There is a small bug in the Issue object.
"return _workItems ?? new List();" could return a new WorkItem on every get if _workItems ever became null. Here is the fixed version.
public class Issue {
public Issue() {
WorkItems = new List<WorkItem>();
}
public String Id {
get; set;
}
public List<WorkItem> WorkItems { get; private set; }
}

Fluent-nHibernate possible way to get rid of proxy members in returning object

I have a class and a map for this class
public class TestClass
{
public virtual Subcategory SubCategory { get; set; }
}
public TestClassMuMap()
{
Id(e => e.Id).Column("ID").GeneratedBy.Assigned();
References(x => x.SubCategory).Column("Subcategory");
}
In received objects I found new member SubcategoryProxyf528587c5459469ba2347093600432d8
How can I get rid of it?
Not.LazyLoad() shoud do it:
References(x => x.SubCategory).Not.LazyLoad().Column("Subcategory");
But LazyLoad is a good thing, check if you really have problem with getting proxy
What is LazyLoad?
Collections (other than arrays) may be lazily initialized, meaning
they load their state from the database only when the application
needs to access it. Initialization happens transparently to the user
so the application would not normally need to worry about this.
Read more in the docs
On the project site, you'll find an extension class NHibernateUnProxyExtension which will do the work for you:
public static class NHibernateUnProxyExtension
{
/// <summary>
/// Recursively removes NHibernate proxies from an object. Do not use session.Save(objt) or session.Update(objt) after unproxying, you might lose important data
/// </summary>
public static void UnProxy(this object objt)
{
for (int i = 0; i < objt.GetType().GetProperties().Count(); i++)
{
try
{
PropertyInfo propertyInfo = objt.GetType().GetProperties()[i];
var propValue = propertyInfo.GetValue(objt, null);
if (propValue.IsProxy())
{
System.Type objType = NHibernateProxyHelper.GetClassWithoutInitializingProxy(propValue);
//Creates a new NonProxyObject
object NonProxyObject = Activator.CreateInstance(objType);
//Copy everything that it can be copied
foreach (var prop in propValue.GetType().GetProperties())
{
try
{
object a = prop.GetValue(propValue);
NonProxyObject.GetType().GetProperty(prop.Name).SetValue(NonProxyObject, a);
}
catch { }
}
//Change the proxy to the real class
propertyInfo.SetValue(objt, NonProxyObject);
}
//Lists
if (propValue.GetType().IsGenericType && propValue.GetType().GetGenericTypeDefinition() == typeof(PersistentGenericBag<>))
{
try
{
int count = (int)(propValue.GetType().GetProperty("Count").GetValue(propValue));
}
catch { propertyInfo.SetValue(objt, null); }
}
if (propValue.GetType().Assembly.GetName().Name != "mscorlib" &&
propValue.GetType().Assembly.GetName().Name != "NHibernate")
{
// user-defined!
propValue.UnProxy();
}
}
catch { }
}
}
}

Categories