How to get relationships with properties from Neo4jClient - neo4j

After some struggle to get it right I manage to save relationships with properties to a Neo4j db with Neo4jClient. The problem arrises when I want to read those relationships back. Suddenly the query which worked like a charm before does not return my users anymore? No exceptions are thrown, the call just silently returns empty :( I read about possible deserializing problems and added the parameterless constructor to the relationship class but no luck.
public class UserHasHomeCity : Relationship<HasHomeCity>, IRelationshipAllowingSourceNode<UserEntity>, IRelationshipAllowingTargetNode<CityEntity>
{
public UserHasHomeCity()
: base(-1, null)
{
}
public UserHasHomeCity(NodeReference targetNode, HasHomeCity data)
: base(targetNode, data)
{
}
public const string TypeKey = "USER_HAS_HOME_CITY";
public override string RelationshipTypeKey
{
get { return TypeKey; }
}
}
public class HasHomeCity
{
public string Date { get; set; }
public HasHomeCity()
{ }
public HasHomeCity(string date)
{
this.Date = date;
}
}
And here is my query:
var graphResults = graphClient.Cypher
.Match("(user:User)-[:USER_IS_IN_ROLE]-(role:Role)",
"(user:User)-[:USER_HAS_HOME_CITY]-(homeCity:City)-[:CITY_IS_IN_COUNTRY]-(homeCountry:Country)",
"(user:User)-[:USER_HAS_LIVING_CITY]-(livingCity:City)-[:CITY_IS_IN_COUNTRY]-(livingCountry:Country)")
.Where((UserEntity user) => user.Id == id)
.Return((user, role, homeCity, livingCity, homeCountry, livingCountry) => new
{
User = user.As<UserEntity>(),
Roles = role.CollectAs<RoleEntity>(),
HomeCity = homeCity.As<CityEntity>(),
LivingCity = livingCity.As<CityEntity>(),
HomeCountry = homeCountry.As<CountryEntity>(),
LivingCountry = livingCountry.As<CountryEntity>()
}).Results;

Neo4jClient is moving away from using Relationship and Node classes where possible, so, the good news is - you don't need to define your relationships as : Relationship any more! In fact, depending on how far you want to take it, you don't even need your UserHasHomeCity class at all!
Relationship properties are treated the same as nodes, in the sense that they are just POCO objects.
So, to create (as I'm sure you know) we do something like:
var userData = new User {Id = "Id-1"};
var cityData = new City {Name = "Brighton"};
var countryData = new Country {Name = "UK"};
var userHasHomeData = new HasHomeCity {Date = "April 1980"};
var generalData = new CountryRelationshipData { Area = "South Coast" };
gc.Cypher
.Create("(country:Country {countryParams})")
.WithParam("countryParams", countryData)
.ExecuteWithoutResults();
gc.Cypher
.Match("(country:Country)")
.Where((Country country) => country.Name == "UK")
.CreateUnique("(city:City {cityParams})-[:CITY_IS_IN_COUNTRY {relParams}]->(country)")
.WithParam("cityParams", cityData)
.WithParam("relParams", generalData)
.ExecuteWithoutResults();
gc.Cypher
.Match("(city:City)")
.Where((City city) => city.Name == "Brighton")
.Create("(user:User {userParams})-[:USER_HAS_HOME_CITY {relParams}]->(city)")
.WithParam("userParams", userData)
.WithParam("relParams", userHasHomeData )
.ExecuteWithoutResults();
which will give us a (User)-[:USER_HAS_HOME_CITY]-(City) structure.
To retrieve the relationship properties, we can use this query:
var query = gc.Cypher
.Match("(user:User)-[r:USER_HAS_HOME_CITY]-(city:City)-[r1:CITY_IS_IN_COUNTRY]-(country:Country)")
.Where((User user) => user.Id == "Id-1")
.Return((user, city, r, country, r1) =>
new
{
User = user.As<User>(),
City = city.As<City>(),
HasHome = r.As<HasHomeCity>(),
Country = country.As<Country>(),
CountryRel = r1.As<CountryRelationshipData>()
});
and looping through the results (all 1 of them in this case):
var res = query.Results.ToList();
foreach (var result in res)
Console.WriteLine("User ({0}) home city: {1} (which is in {2}, {3}) since {4}", result.User.Id, result.City.Name,result.CountryRel.Area, result.Country.Name, result.HasHome.Date );
will give us:
User (Id-1) home city: Brighton (which is in South Coast, UK) since April 1980
as the output.

Related

Best Way to Update only modified fields with Entity Framework

Currently I am doing like this:
For Example:
public update(Person model)
{
// Here model is model return from form on post
var oldobj = db.Person.where(x=>x.ID = model.ID).SingleOrDefault();
db.Entry(oldobj).CurrentValues.SetValues(model);
}
It works, but for example,
I have 50 columns in my table but I displayed only 25 fields in my form (I need to partially update my table, with remaining 25 column retain same old value)
I know it can be achieve by "mapping columns one by one" or by creating "hidden fields for those remaining 25 columns".
Just wondering is there any elegant way to do this with less effort and optimal performance?
This is a very good question. By default I have found that as long as change tracking is enabled (it is by default unless you turn it off), Entity Framework will do a good job of applying to the database only what you ask it to change.
So if you only change 1 field against the object and then call SaveChanges(), EF will only update that 1 field when you call SaveChanges().
The problem here is that when you map a view model into an entity object, all of the values get overwritten. Here is my way of handling this:
In this example, you have a single entity called Person:
Person
======
Id - int
FirstName - varchar
Surname - varchar
Dob - smalldatetime
Now let's say we want to create a view model which will only update Dob, and leave all other fields exactly how they are, here is how I do that.
First, create a view model:
public class PersonDobVm
{
public int Id { get; set; }
public DateTime Dob { get; set; }
public void MapToModel(Person p)
{
p.Dob = Dob;
}
}
Now write the code roughly as follows (you'll have to alter it to match your context name etc):
DataContext db = new DataContext();
Person p = db.People.FirstOrDefault();
// you would have this posted in, but we are creating it here just for illustration
var vm = new PersonDobVm
{
Id = p.Id, // the Id you want to update
Dob = new DateTime(2015, 1, 1) // the new DOB for that row
};
vm.MapToModel(p);
db.SaveChanges();
The MapToModel method could be even more complicated and do all kinds of additional checks before assigning the view model fields to the entity object.
Anyway, the result when SaveChanges is called is the following SQL:
exec sp_executesql N'UPDATE [dbo].[Person]
SET [Dob] = #0
WHERE ([Id] = #1)
',N'#0 datetime2(7),#1 int',#0='2015-01-01 00:00:00',#1=1
So you can clearly see, Entity Framework has not attempted to update any other fields - just the Dob field.
I know in your example you want to avoid coding each assignment by hand, but I think this is the best way. You tuck it all away in your VM so it does not litter your main code, and this way you can cater for specific needs (i.e. composite types in there, data validation, etc). The other option is to use an AutoMapper, but I do not think they are safe. If you use an AutoMapper and spelt "Dob" as "Doob" in your VM, it would not map "Doob" to "Dob", nor would it tell you about it! It would fail silently, the user would think everything was ok, but the change would not be saved.
Whereas if you spelt "Dob" as "Doob" in your VM, the compiler will alert you that the MapToModel() is referencing "Dob" but you only have a property in your VM called "Doob".
I hope this helps you.
I swear by EntityFramework.Extended. Nuget Link
It lets you write:
db.Person
.Where(x => x.ID == model.ID)
.Update(p => new Person()
{
Name = newName,
EditCount = p.EditCount+1
});
Which is very clearly translated into SQL.
Please try this way
public update(Person model)
{
// Here model is model return from form on post
var oldobj = db.Person.where(x=>x.ID = model.ID).SingleOrDefault();
// Newly Inserted Code
var UpdatedObj = (Person) Entity.CheckUpdateObject(oldobj, model);
db.Entry(oldobj).CurrentValues.SetValues(UpdatedObj);
}
public static object CheckUpdateObject(object originalObj, object updateObj)
{
foreach (var property in updateObj.GetType().GetProperties())
{
if (property.GetValue(updateObj, null) == null)
{
property.SetValue(updateObj,originalObj.GetType().GetProperty(property.Name)
.GetValue(originalObj, null));
}
}
return updateObj;
}
I have solved my Issue by using FormCollection to list out used element in form, and only change those columns in database.
I have provided my code sample below; Great if it can help someone else
// Here
// collection = FormCollection from Post
// model = View Model for Person
var result = db.Person.Where(x => x.ID == model.ID).SingleOrDefault();
if (result != null)
{
List<string> formcollist = new List<string>();
foreach (var key in collection.ToArray<string>())
{
// Here apply your filter code to remove system properties if any
formcollist.Add(key);
}
foreach (var prop in result.GetType().GetProperties())
{
if( formcollist.Contains(prop.Name))
{
prop.SetValue(result, model.GetType().GetProperty(prop.Name).GetValue(model, null));
}
}
db.SaveChanges();
}
I still didn't find a nice solution for my problem, so I created a work around. When loading the Entity, I directly make a copy of it and name it entityInit. When saving the Entity, I compare the both to see, what really was changed. All the unchanged Properties, I set to unchanged and fill them with the Database-Values. This was necessary for my Entities without Tracking:
// load entity without tracking
var entityWithoutTracking = Context.Person.AsNoTracking().FirstOrDefault(x => x.ID == _entity.ID);
var entityInit = CopyEntity(entityWithoutTracking);
// do business logic and change entity
entityWithoutTracking.surname = newValue;
// for saving, find entity in context
var entity = Context.Person.FirstOrDefault(x => x.ID == _entity.ID);
var entry = Context.Entry(entity);
entry.CurrentValues.SetValues(entityWithoutTracking);
entry.State = EntityState.Modified;
// get List of all changed properties (in my case these are all existing properties, including those which shouldn't have changed)
var changedPropertiesList = entry.CurrentValues.PropertyNames.Where(x => entry.Property(x).IsModified).ToList();
foreach (var checkProperty in changedPropertiesList)
{
try
{
var p1 = entityWithoutTracking.GetType().GetProperty(checkProperty).GetValue(entityWithoutTracking);
var p2 = entityInit.GetType().GetProperty(checkProperty).GetValue(entityInit);
if ((p1 == null && p2 == null) || p1.Equals(p2))
{
entry.Property(checkProperty).CurrentValue = entry.Property(checkProperty).OriginalValue; // restore DB-Value
entry.Property(checkProperty).IsModified = false; // throws Exception for Primary Keys
}
} catch(Exception) { }
}
Context.SaveChanges(); // only surname will be updated
This is way I did it, assuming the new object has more columns to update that the one we want to keep.
if (theClass.ClassId == 0)
{
theClass.CreatedOn = DateTime.Now;
context.theClasses.Add(theClass);
}
else {
var currentClass = context.theClasses.Where(c => c.ClassId == theClass.ClassId)
.Select(c => new TheClasses {
CreatedOn = c.CreatedOn
// Add here others fields you want to keep as the original record
}).FirstOrDefault();
theClass.CreatedOn = currentClass.CreatedOn;
// The new class will replace the current, all fields
context.theClasses.Add(theClass);
context.Entry(theClass).State = EntityState.Modified;
}
context.SaveChanges();
In EF you can do like this
var result = db.Person.Where(x => x.ID == model.ID).FirstOrDefault();
if(result != null){
result.Name = newName;
result.DOB = newDOB;
db.Person.Update(result);
}
Or you can use
using (var db= new MyDbContext())
{
var result= db.Person.Where(x => x.ID == model.ID).FirstOrDefault();
result.Name= newName;
result.DOB = newDOB;
db.Update(result);
db.SaveChanges();
}
For more detail please EntityFramework Core - Update Only One Field
No Worry guys
Just write raw sql query
db.Database.ExecuteSqlCommand("Update Person set Name='"+_entity.Name+"' where Id = " + _entity.ID + "");

using GroupPrincipal can you get additional info from UserPrincipal

I am looking up users who are members of an AD group using GroupPrincipal.
GroupPrincipal group = GroupPrincipal.FindByIdentity(pc, "Advisors");
I need to get the EmployeeID field from this lookup but I believe this is only possible using UserPrincipal.
var members = group.Members.Select(x => new DomainContext() { EmployeeID = x.EmployeeId, FullName = x.DisplayName }).ToList();
Does anyone know of a way round this?
You have to use UserPrincipal unless you're using the underlying DirectoryEntry/DirectorySearcher classes.
You should use .GetMembers() instead of .Members then you can do stuff like:
var userMembers = group.GetMembers().OfType<UserPrincipal>();
foreach( var member in userMembers) {
string empid = member.EmployeeId; //do something with the EmployeeId
}

How to write Nunit TestCases to test the correct List of strings is returned

I have a method like:
public virtual IList<string> Validate()
{
...
}
I want to unit test this using NUnit. This is part of a class Vehicle.
A Vehicle can be of different types ie. Car Boat Truck etc.
At the top of my TestFixture I set up the VehicleTypes:
private VehicleType[] _vehicleTypes;
[SetUp]
public void MyTestInitialize()
{
transScope = new TransactionScope();
var boat= new VehicleType { Name = "boat" };
var car = new VehicleType { Name = "car" };
var truck = new VehicleType { Name = "truck" };
_vehicleTypes= new VehicleType[] { boat, car, truck };
...
}
What I want is to test that an error message is sent back from the method for the boat only.
My unit test is as follows:
[TestCase(0, "This vehicle is inappropriate because it doesn't have wheels")]
[TestCase(1, null)]
[TestCase(2, null)]
public void Validate_Vehicle_ReturnsAppropriateErrorMessage(int vehicleType, string expectedResult)
{
var vehicle = new Vehicle { VehicleType = _vehicleTypes[vehicleType] };
var results = vehicle.Validate();
string result;
if (results.Count == 0)
result = null;
else
result = results[0];
Assert.IsTrue(expectedResult == result);
}
So this was how I was trying to test it using TestCases. However I'm not sure this is the right approach as unit tests shouldn't contain ifs?
Also maybe this is a weird approach to writing a test for different types?
Anyone have any better suggestions?
I would break these up into multiple tests. By doing so you can write one that test the normal behavior (non boat) as well as the boat. If any of these test fail in the future, you won't have to try and figure out what iteration of the data driven tests failed. The test will speak for itself.
In this case I would write one for the behavior for the boat and one for the non boat. The other iterations aren't interesting (and likly use the same code path this test is validating as the other non boats)
public void Validate_VehicleIsBoat_ReturnsAppropriateErrorMessage()
{
string expectedResult = "This vehicle is inappropriate because it doesn't have wheels";
var vehicle = new Vehicle { VehicleType = VehicleType.Boat }; //or whatever it is in your enum
var results = vehicle.Validate();
Assert.AreEqual( expectedResult, results[0] );
}
public void Validate_VehicleIsNotBoat_DoesNotReturnErrorMessage()
{
var vehicle = new Vehicle { VehicleType = VehicleType.Car }; //or whatever it is in your enum
var results = vehicle.Validate();
Assert.IsNull( results ); // or whatever the no error message case is. Will results[0] have an empty string?
}
You could add additional tests to validate the result sets have all the data you want as well.
Anyway, hope this helps

Enity Framework 4.1 - One trip database update

Let's say I have this code:
class Score
{
public Update(int score)
{
update score but do not call (context.SaveChanges())
}
}
class Foo
{
public DoSomething(int update)
{
Score score = new Score();
score.Update(2);
SomeObj obj = (select object);
obj.Soo = 3;
context.SaveChanges();
}
}
Basically to make it work, I need to explicity provide SaveChanges in method Update. But when I have 4 such methods in row, and 34243 users want to update data, I don't think saving for each one in 4 trips would be a good idea.
Is there way in EF4.1 to delay database update the last moment, in provided example, Or I'm forced to explicity save for each method ?
EDIT:
For clarification. I tried to do not call SaveChanges in external method, and only one time where the changes mu be saved.
I will give an real example:
public class ScoreService : IScoreService
{
private JamiContext _ctx;
private IRepository<User> _usrRepo;
public ScoreService(IRepository<User> usrRepo)
{
_ctx = new JamiContext();
_usrRepo = usrRepo;
}
public void PostScore(int userId, GlobalSettings gs, string name)
{
User user = _ctx.UserSet.Where(x => x.Id == userId).FirstOrDefault();
if (name == "up")
{
user.Rating = user.Rating + gs.ScoreForLike;
}
else if (name == "down")
{
user.Rating = user.Rating - Math.Abs(gs.ScoreForDislike);
}
}
}
And Now:
public PostRating LikeDislike(User user, int postId, int userId, GlobalSettings set, string name)
{
PostRating model = new PostRating();
var post = (from p in _ctx.PostSet
where p.Id == postId
select p).FirstOrDefault();
if (name == "up")
{
post.Like = post.Like + 1;
model.Rating = post.Like - post.Dislike;
}
else if (name == "down")
{
post.Dislike = post.Dislike + 1;
model.Rating = post.Like - post.Dislike;
}
PostVote pv = new PostVote();
pv.PostId = post.Id;
pv.UserId = user.Id;
_ctx.PostVoteSet.Add(pv);
_scoreSrv.PostScore(userId, set, name);
_ctx.SaveChanges();
return model;
}
I this case user rating do not update, Until I call SaveChanges in PostScore
In your example it looks like PostScore and LikeDislike use different context instances. That is the source of your problem and there is no way to avoid calling multiple SaveChanges in that case. The whole operation is single unit of work and because of that it should use single context instance. Using multiple context instances in this case is wrong design.
Anyway even if you call single SaveChanges you will still have separate roundtrip to the database for each updated, inserted or deleted entity because EF doesn't support command batching.
The way to delay database update to the last moment is by not calling SaveChanges until the last moment.
You have complete control over this code, and if your code is calling SaveChanges after every update, then that needs changing.
This not really solves my entire problem, but at least I can use single instance of Context:
With Ninject:
Bind<JamiContext>().To<JamiContext>().InRequestScope();
And then constructor:
private JamiContext _ctx;
private IRepository<User> _usrRepo;
public ScoreService(IRepository<User> usrRepo, JamiContext ctx)
{
_ctx = ctx;
_usrRepo = usrRepo;
}

Linq to SQL using Repository Pattern: Object has no supported translation to SQL

I have been scratching my head all morning behind this but still haven't been able to figure out what might be causing this.
I have a composite repository object that references two other repositories. I'm trying to instantiate a Model type in my LINQ query (see first code snippet).
public class SqlCommunityRepository : ICommunityRepository
{
private WebDataContext _ctx;
private IMarketRepository _marketRepository;
private IStateRepository _stateRepository;
public SqlCommunityRepository(WebDataContext ctx, IStateRepository stateRepository, IMarketRepository marketRepository)
{
_ctx = ctx;
_stateRepository = stateRepository;
_marketRepository = marketRepository;
}
public IQueryable<Model.Community> Communities
{
get
{
return (from comm in _ctx.Communities
select new Model.Community
{
CommunityId = comm.CommunityId,
CommunityName = comm.CommunityName,
City = comm.City,
PostalCode = comm.PostalCode,
Market = _marketRepository.GetMarket(comm.MarketId),
State = _stateRepository.GetState(comm.State)
}
);
}
}
}
The repository objects that I'm passing in look like this
public class SqlStateRepository : IStateRepository
{
private WebDataContext _ctx;
public SqlStateRepository(WebDataContext ctx)
{
_ctx = ctx;
}
public IQueryable<Model.State> States
{
get
{
return from state in _ctx.States
select new Model.State()
{
StateId = state.StateId,
StateName = state.StateName
};
}
}
public Model.State GetState(string stateName)
{
var s = (from state in States
where state.StateName.ToLower() == stateName
select state).FirstOrDefault();
return new Model.State()
{
StateId = s.StateId,
StateName = s.StateName
};
}
AND
public class SqlMarketRepository : IMarketRepository
{
private WebDataContext _ctx;
public SqlMarketRepository(WebDataContext ctx)
{
_ctx = ctx;
}
public IQueryable<Model.Market> Markets
{
get
{
return from market in _ctx.Markets
select new Model.Market()
{
MarketId = market.MarketId,
MarketName = market.MarketName,
StateId = market.StateId
};
}
}
public Model.Market GetMarket(int marketId)
{
return (from market in Markets
where market.MarketId == marketId
select market).FirstOrDefault();
}
}
This is how I'm wiring it all up:
WebDataContext ctx = new WebDataContext();
IMarketRepository mr = new SqlMarketRepository(ctx);
IStateRepository sr = new SqlStateRepository(ctx);
ICommunityRepository cr = new SqlCommunityRepository(ctx, sr, mr);
int commCount = cr.Communities.Count();
The last line in the above snippet is where it fails. When I debug through the instantiation (new Model.Community), it never goes into any of the other repository methods. I do not have a relationship between the underlying tables behind these three objects. Would this be the reason that LINQ to SQL is not able to build the expression tree right?
These are non-hydrated queries, not fully-hydrated collections.
The Communities query differs from the other two because it calls methods as objects are hydrated. These method calls are not translatable to SQL.
Normally this isn't a problem. For example: if you say Communities.ToList(), it will work and the methods will be called from the objects as they are hydrated.
If you modify the query such that the objects aren't hydrated, for example: when you say Communities.Count(), linq to sql attempts to send the method calls into the database and throws since it cannot. It does this even though those method calls ultimately would not affect the resulting count.
The simplest fix (if you truly expect fully hydrated collections) is to add ToList to the community query, hydrating it.
Try adding another repository method that looks like this:
public int CommunitiesCount()
{
get { return _ctx.Communities.Count(); }
}
This will allow you to return a count without exposing the entire object tree to the user, which is what I think you're trying to do anyway.
As you may have already guessed, I suspect that what you are calling the anonymous types are at fault (they're not really anonymous types; they are actual objects, which you are apparently partially populating in an effort to hide some of the fields from the end user).

Resources