NHibernate.QueryException Message : duplicate association path - c#

I have this code:
if (pertinentDataExists) {
List<Entity> operatorList = new List<Operator>();
List<Entity> newOperatorList = criteria.newOperatorList;
foreach (Operator operator in operatorList)
{
operatorList.Add(operator);
}
queryCriteria.CreateCriteria("OperatorList").Add(Restrictions.In("Operator", operatorList));
}
and then later:
if (otherPertinentDataExists) {
Object[] objects = new Object[criteria.newRoleTypeList.Count];
for (int = 0; i < criteria.RoleTypeList.Count; i++) {
objects[i] = criteria.RoleTypeList[i].Id;
}
queryCriteria.CreateCriteria("OperatorList").Add(Restrictions.In("Role", objects));
}
These work separately just fine. However, if it is the case that both cases have criteria to add to the list, then I get:
NHibernate.QueryException Message : duplicate association path:
OperatorList
How do I add restrictions for Role if the criteria is already created?

There are two options. The first, if possible (being in the same method), create Criteria and reference them as a local variable:
var operatorListCriteria = queryCriteria.CreateCriteria("OperatorList");
if ( myCondition1 )
{
operatorListCriteria.Add(...
}
if ( myCondition2 )
{
operatorListCriteria.Add(...
}
The second, create criteria with "alias" and then, later, anywhere, you can find them with GetCriteriaByAlias(aliasPath):
var aliasPath = "OperatorListAlias";
var operatorListCriteria = queryCriteria.CreateCriteria("OperatorList", aliasPath);
...
// later find them by aliasPath
var subCriteria = queryCriteria.GetCriteriaByAlias(aliasPath);
NOTE: Also check the GetCriteriaByPath(associationPath)

Related

Merge data from two arrays or something else

How to combine Id from the list I get from file /test.json and id from list ourOrders[i].id?
Or if there is another way?
private RegionModel FilterByOurOrders(RegionModel region, List<OurOrderModel> ourOrders, MarketSettings market, bool byOurOrders)
{
var result = new RegionModel
{
updatedTs = region.updatedTs,
orders = new List<OrderModel>(region.orders.Count)
};
var json = File.ReadAllText("/test.json");
var otherBotOrders = JsonSerializer.Deserialize<OrdersTimesModel>(json);
OtherBotOrders = new Dictionary<string, OrderTimesInfoModel>();
foreach (var otherBotOrder in otherBotOrders.OrdersTimesInfo)
{
//OtherBotOrders.Add(otherBotOrder.Id, otherBotOrder);
BotController.WriteLine($"{otherBotOrder.Id}"); //Output ID orders to the console works
}
foreach (var order in region.orders)
{
if (ConvertToDecimal(order.price) < 1 || !byOurOrders)
{
int i = 0;
var isOurOrder = false;
while (i < ourOrders.Count && !isOurOrder)
{
if (ourOrders[i].id.Equals(order.id, StringComparison.InvariantCultureIgnoreCase))
{
isOurOrder = true;
}
++i;
}
if (!isOurOrder)
{
result.orders.Add(order);
}
}
}
return result;
}
OrdersTimesModel Looks like that:
public class OrdersTimesModel
{
public List<OrderTimesInfoModel> OrdersTimesInfo { get; set; }
}
test.json:
{"OrdersTimesInfo":[{"Id":"1"},{"Id":"2"}]}
Added:
I'll try to clarify the question:
There are three lists with ID:
First (all orders): region.orders, as order.id
Second (our orders): ourOrders, as ourOrders[i].id in a while loop
Third (our orders 2): from the /test.json file, as an array {"Orders":[{"Id":"12345..."...},{"Id":"12345..." ...}...]}
There is a foreach in which there is a while, where the First (all orders) list and the Second (our orders) list are compared. If the id's match, then these are our orders: isOurOrder = true;
Accordingly, those orders that isOurOrder = false; will be added to the result: result.orders.Add(order)
I need:
So that if (ourOrders[i].id.Equals(order.id, StringComparison.InvariantCultureIgnoreCase)) would include more Id's from the Third (our orders 2) list.
Or any other way to do it?
You should be able to completely avoid writing loops if you use LINQ (there will be loops running in the background, but it's way easier to read)
You can access some documentation here: https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/concepts/linq/introduction-to-linq-queries
and you have some pretty cool extension methods for arrays: https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable?view=net-6.0 (these are great to get your code easy to read)
Solution
unsing System.Linq;
private RegionModel FilterByOurOrders(RegionModel region, List<OurOrderModel> ourOrders, MarketSettings market, bool byOurOrders)
{
var result = new RegionModel
{
updatedTs = region.updatedTs,
orders = new List<OrderModel>(region.orders.Count)
};
var json = File.ReadAllText("/test.json");
var otherBotOrders = JsonSerializer.Deserialize<OrdersTimesModel>(json);
// This line should get you an array containing
// JUST the ids in the JSON file
var idsFromJsonFile = otherBotOrders.Select(x => x.Id);
// Here you'll get an array with the ids for your orders
var idsFromOurOrders = ourOrders.Select(x => x.id);
// Union will only take unique values,
// so you avoid repetition.
var mergedArrays = idsFromJsonFile.Union(idsFromOurOrders);
// Now we just need to query the region orders
// We'll get every element that has an id contained in the arrays we created earlier
var filteredRegionOrders = region.orders.Where(x => !mergedArrays.Contains(x.id));
result.orders.AddRange(filteredRegionOrders );
return result;
}
You can add conditions to any of those actions (like checking for order price or the boolean flag you get as a parameter), and of course you can do it without assigning so many variables, I did it that way just to make it easier to explain.

How do I create a new root by adding and removing nodes retrieved from the old root?

I am creating a Code Fix that changes this:
if(obj is MyClass)
{
var castedObj = obj as MyClass;
}
into this:
var castedObj = obj as MyClass;
if(castedObj != null)
{
}
This means I have to do 3 things:
Change the condition in the if statement.
Move the casting right above the if statement.
Remove the statement in the body.
So far, all my attempts have stranded me at getting at most 2 of these things to work.
I believe this problem occurs because you basically have 2 syntax nodes on the same level. As such, making a change to one of them invalidates the location of the other one. Or something like that. Long story short: I either manage to copy the variable assignment outside the if statement, or I manage to change the condition + remove the variable assignment. Never all 3.
How would I solve this?
For good measure, here is my code which changes the condition and removes the assignment:
var newIfStatement = ifStatement.RemoveNode(
variableDeclaration,
SyntaxRemoveOptions.KeepExteriorTrivia);
newIfStatement = newIfStatement.ReplaceNode(newIfStatement.Condition, newCondition);
var ifParent = ifStatement.Parent;
var newParent = ifParent.ReplaceNode(ifStatement, newIfStatement);
newParent = newParent.InsertNodesBefore(
newIfStatement,
new[] { variableDeclaration })
.WithAdditionalAnnotations(Formatter.Annotation);
var newRoot = root.ReplaceNode(ifParent, newParent);
Have you looked at the DocumentEditor class ? It is very useful when dealing with modifying syntax, especially when the changes that are applied to the tree might cause invalidation problems. The operations are pretty much the same as the ones you already have defined, just use the DocumentEditor methods instead and see if that helps. I can't verify if that solves your problem ATM, but I think it solved the a similar problem for me once in the past. I'll test it out later if I can.
Something like this will do it:
var editor = await DocumentEditor.CreateAsync(document);
editor.RemoveNode(variableDeclaration);
editor.ReplaceNode(ifStatement.Condition, newCondition);
editor.InsertBefore(ifStatement,
new[] { variableDeclaration.WithAdditionalAnnotations(Formatter.Annotation) });
var newDocument = editor.GetChangedDocument();
I have managed to do something very similar in the following manner.
I extract the while condition and move it before the while and replace the condition with a new node.
In the body of while, I add a new statement.
In your case, instead of adding a statement, you will remove the desired statement from the body.
Start at
Refactor(BlockSyntax oldBody)
STEP 1: I first visit and mark the nodes that I want to change and at the same time generate new nodes, but don't add the new ones yet.
STEP 2: Track the marked nodes and replace with new ones.
class WhileConditionRefactoringVisitor : CSharpSyntaxRewriter
{
private static int CONDITION_COUNTER = 0;
private static string CONDITION_VAR = "whileCondition_";
private static string ConditionIdentifier
{
get { return CONDITION_VAR + CONDITION_COUNTER++; }
}
private readonly List<SyntaxNode> markedNodes = new List<SyntaxNode>();
private readonly List<Tuple<ExpressionSyntax, IdentifierNameSyntax, StatementSyntax, WhileStatementSyntax>> replacementNodes =
new List<Tuple<ExpressionSyntax, IdentifierNameSyntax, StatementSyntax, WhileStatementSyntax>>();
//STEP 1
public override SyntaxNode VisitWhileStatement(WhileStatementSyntax node)
{
var nodeVisited = (WhileStatementSyntax) base.VisitWhileStatement(node);
var condition = nodeVisited.Condition;
if (condition.Kind() == SyntaxKind.IdentifierName)
return nodeVisited;
string conditionVarIdentifier = ConditionIdentifier;
var newConditionVar = SyntaxFactoryExtensions.GenerateLocalVariableDeclaration(conditionVarIdentifier,
condition, SyntaxKind.BoolKeyword).NormalizeWhitespace().WithTriviaFrom(nodeVisited);
var newCondition = SyntaxFactory.IdentifierName(conditionVarIdentifier).WithTriviaFrom(condition);
markedNodes.Add(condition);
markedNodes.Add(node);
replacementNodes.Add(new Tuple<ExpressionSyntax, IdentifierNameSyntax, StatementSyntax, WhileStatementSyntax>(condition, newCondition, newConditionVar, node));
return nodeVisited;
}
//STEP 2
private BlockSyntax ReplaceNodes(BlockSyntax oldBody)
{
oldBody = oldBody.TrackNodes(this.markedNodes);
foreach (var tuple in this.replacementNodes)
{
var currentA = oldBody.GetCurrentNode(tuple.Item1);
if (currentA != null)
{
var whileStatement = currentA.Parent;
oldBody = oldBody.InsertNodesBefore(whileStatement, new List<SyntaxNode>() { tuple.Item3 });
var currentB = oldBody.GetCurrentNode(tuple.Item1);
oldBody = oldBody.ReplaceNode(currentB, tuple.Item2);
var currentWhile = oldBody.GetCurrentNode(tuple.Item4);
//modify body
var whileBody = currentWhile.Statement as BlockSyntax;
//create new statement
var localCondition = tuple.Item3 as LocalDeclarationStatementSyntax;
var initializer = localCondition.Declaration.Variables.First();
var assignment = SyntaxFactory.ExpressionStatement(SyntaxFactory.AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
SyntaxFactory.IdentifierName(initializer.Identifier), initializer.Initializer.Value));
var newStatements = whileBody.Statements.Add(assignment);
whileBody = whileBody.WithStatements(newStatements);
//updateWhile
var newWhile = currentWhile.WithStatement(whileBody);
oldBody = oldBody.ReplaceNode(currentWhile, newWhile);
}
}
return oldBody;
}
public BlockSyntax Refactor(BlockSyntax oldBody)
{
markedNodes.Clear();
replacementNodes.Clear();
//STEP 1
oldBody = (BlockSyntax)this.Visit(oldBody);
//STEP 2
oldBody = this.ReplaceNodes(oldBody);
return oldBody;
}
}

How can I edit or add to a particular field without pull the all object

How I can do just this ( a.myFavorits.Add()) without pulling the all object to var a , because a has a lot of data, and I don't want to pull all a object, but I can't find a way do do it.
I want to do the lambada and the linq without return something but linq is always return something
public static void addFavorits(long f,long idUser)
{
using (var db = dataBase())
{
// here i pull object user from users table
var a = db.users.Where(c => c.id == idUser).SingleOrDefault();
// here i adding to the object field myFavorits new value
//myFavorits is also a table of entitys that connected to user object
a.myFavorits.Add(new BE.FavoritsUsersLong { myLong = f });
db.SaveChanges();
}
}
I thought to do something like this but i dont know how to set the field users_TableId that is the key that connect the 2 tables
public static void addFavorits(long favoritId,long idUser)
{
using (var db = dataBase())
{
db.favoritsUsersLong.Add(new BE.FavoritsUsersLong {myLong = favoritId}
/*,users_TableId =idUser*/);
db.SaveChanges();
}
}
Here's a concrete example that does what you want. In this example, only the Name of a Company is modified and saved. Or an item is added to one of its collections.
var cmp = new Company{ CmpId = 1, Name = "Cmp1" }; // CmpId is the primary key
db.Companies.Attach(cmp);
db.Entry(cmp).Property(c => c.Name).IsModified = true;
// Or add an entity to a collection:
cmp.Users = new[] {new User { Name = "a1", PassWord = "a1" } };
try
{
db.Configuration.ValidateOnSaveEnabled = false;
db.SaveChanges();
}
finally
{
db.Configuration.ValidateOnSaveEnabled = true;
}
Result in SQL:
DECLARE #0 VarChar(30) = 'Cmp1'
DECLARE #1 Int = 1
UPDATE [dbo].[Company]
SET [Name] = #0
WHERE ([CmpId] = #1)
There are a few things to note here:
Obviously you need to know the Id of the entity you want to modify.
The object you create is called a stub entity, which is an incomplete entity. When you try to save such an entity, EF is very likely to complain about null values in required properties. That's why almost certain you'd have to disable validation (temporarily, or, better, dispose the context immediately).
If you want to add an item to a collection, you should leave validation enabled, because you'd want to know for sure that the new entity is valid. So you shouldn't mix these two ways to use a stub entity.
If you often need roughly the same small part of your entity you may consider table splitting.
I'm guessing this is what you want? I don't see you 'editting' I only see you adding.
using (var db = dataBase())
{
var a = new user();
....
//set properties etc..
...
a.myFavorits.Add(new BE.FavoritsUsersLong { myLong = f });
db.users.Add(a);
db.SaveChanges();
}

Concurent foreach iteration of two list strings

Let's say I have two List<string>. These are populated from the results of reading a text file
List owner contains:
cross
jhill
bbroms
List assignee contains:
Chris Cross
Jack Hill
Bryan Broms
During the read from a SQL source (the SQL statement contains a join)... I would perform
if(sqlReader["projects.owner"] == "something in owner list" || sqlReader["assign.assignee"] == "something in assignee list")
{
// add this projects information to the primary results LIST
list_by_owner.Add(sqlReader["projects.owner"],sqlReader["projects.project_date_created"],sqlReader["projects.project_name"],sqlReader["projects.project_status"]);
// if the assignee is not null, add also to the secondary results LIST
// logic to determine if assign.assignee is null goes here
list_by_assignee.Add(sqlReader["assign.assignee"],sqlReader["projects.owner"],sqlReader["projects.project_date_created"],sqlReader["projects.project_name"],sqlReader["projects.project_status"]);
}
I do not want to end up using nested foreach.
The FOR loop would probably suffice. Someone had mentioned ZIP to me but wasn't sure if that would be a preferable route to go in my situation.
One loop to iterate through both lists (assuming both have same count):
for (int i = 0; i < alpha.Count; i++)
{
var itemAlpha = alpha[i] // <= your object of list alpha
var itemBeta = beta[i] // <= your object of list beta
//write your code here
}
From what you describe, you don't need to iterate at all.
This is what you need:
http://msdn.microsoft.com/en-us/library/bhkz42b3.aspx
Usage:
if ((listAlpga.contains(resultA) || (listBeta.contains(resultA)) {
// do your operation
}
List Iteration will happen implicitly inside the contains method. And thats 2n comparisions, vs n*n for nested iteration.
You would be better off with sequential iteration in each list one after the other, if at all you need to go that route.
This list is maybe better represented as a List<KeyValuePair<string, string>> which would pair the two list values together in a single list.
There are several options for this. The least "painful" would be plain old for loop:
for (var index = 0; index < alpha.Count; index++)
{
var alphaItem = alpha[index];
var betaItem = beta[index];
// Do something.
}
Another interesting approach is using the indexed LINQ methods (but you need to remember they get evaluated lazily, you have to consume the resulting enumerable), for example:
alpha.Select((alphaItem, index) =>
{
var betaItem = beta[index];
// Do something
})
Or you can enumerate both collection if you use the enumerator directly:
using (var alphaEnumerator = alpha.GetEnumerator())
using (var betaEnumerator = beta.GetEnumerator())
{
while (alphaEnumerator.MoveNext() && betaEnumerator.MoveNext())
{
var alphaItem = alphaEnumerator.Current;
var betaItem = betaEnumerator.Current;
// Do something
}
}
Zip (if you need pairs) or Concat (if you need combined list) are possible options to iterate 2 lists at the same time.
I like doing something like this to enumerate over parallel lists:
int alphaCount = alpha.Count ;
int betaCount = beta.Count ;
int i = 0 ;
while ( i < alphaCount && i < betaCount )
{
var a = alpha[i] ;
bar b = beta[i] ;
// handle matched alpha/beta pairs
++i ;
}
while ( i < alphaCount )
{
var a = alpha[i] ;
// handle unmatched alphas
++i ;
}
while ( i < betaCount )
{
var b = beta[i] ;
// handle unmatched betas
++i ;
}

Lucene.NET and searching on multiple fields with specific values

I've created an index with various bits of data for each document I've added, each document can differ in it field name.
Later on, when I come to search the index I need to query it with exact field/ values - for example:
FieldName1 = X AND FieldName2 = Y AND FieldName3 = Z
What's the best way of constructing the following using Lucene .NET:
What analyser is best to use for this exact match type?
Upon retrieving a match, I only need one specific field to be returned (which I add to each document) - should this be the only one stored?
Later on I'll need to support keyword searching (so a field can have a list of values and I'll need to do a partial match).
The fields and values come from a Dictionary<string, string>. It's not user input, it's constructed from code.
Thanks,
Kieron
Well, I figured it out eventually - here's my take on it (this could be completely wrong, but it works for):
public Guid? Find (Dictionary<string, string> searchTerms)
{
if (searchTerms == null)
throw new ArgumentNullException ("searchTerms");
try
{
var directory = FSDirectory.Open (new DirectoryInfo (IndexRoot));
if (!IndexReader.IndexExists (directory))
return null;
var mainQuery = new BooleanQuery ();
foreach (var pair in searchTerms)
{
var parser = new QueryParser (
Lucene.Net.Util.Version.LUCENE_CURRENT, pair.Key, GetAnalyzer ());
var query = parser.Parse (pair.Value);
mainQuery.Add (query, BooleanClause.Occur.MUST);
}
var searcher = new IndexSearcher (directory, true);
try
{
var results = searcher.Search (mainQuery, (Filter)null, 10);
if (results.totalHits != 1)
return null;
return Guid.Parse (searcher.Doc (results.scoreDocs[0].doc).Get (ContentIdKey));
}
catch
{
throw;
}
finally
{
if (searcher != null)
searcher.Close ();
}
}
catch
{
throw;
}
}

Categories

Resources