How to attach an object that contains a n to n relation? - c#

I have two tables that are linked n-n. And I have a method that takes one object and saves.
public int Save(Table1 element)
{
using (var database = new Entities())
{
if (element.ID == 0)
{
database.Table1.AddObject(element);
}
else
{
database.Attach(element); //
database.ObjectStateManager.GetObjectStateEntry(element).SetModified();
database.Refresh(RefreshMode.ClientWins, element);
}
return database.SaveChanges();
}
}
When I don't try to modify obj1.Table2 it attaches and saves successfully. But if I try to modify this EntityCollection
element.Table2.Add(tb2);
And save, I get the following error:
An object with a temporary EntityKey value cannot be attached to an object context.
at Line: database.Attach(element);
How can I fix it?
Database:
Table 1 Table 2
ID | Name ID | Name
--------- -------------------
1 | One 1 | Related to One
2 | Two 2 | Related to One
3 | Three
Table 3
Tb1 | Tb2
---------
// 1 | 1
// 1 | 2
Creating Table1 object:
var element = GetTable1Obj(1);
element.Table2.Add(GetTable2Obj(1)); // GetTable2Obj uses a separated context
element.Table2.Add(GetTable2Obj(2)); // like Save method to return the object
provider.Save(element); // Method above

If Your Entity frame work model is set to something like this You should be able to modify t1 or t2 without having issues. while still keeping
From the looks of table 3 in your example you don't have a key for the entries.
Which will cause issues when modifying the Entity Object. What is your DB Fk set at.

Related

Filter table with Json array column by integer value

In EF Core how can I efficiently check if text column of Json array contains any number from passed integer array using LINQ?
Example of table, where Id is integer type and Name and TypeJson are text
| Id | Name | TypeJson |
| --- | ---------- | -------- |
| 1 | Name One | [1,2] |
| 2 | Name Two | [2,3] |
| 3 | Name Three | [4,7] |
In Postgresql I would have written something like this
SELECT *
FROM "Table"
WHERE translate("TypeJson", '[]','{}')::int[] && ARRAY[1, 7]
where the select would return 1 and 3 rows.
I'd like to achieve same result by using LINQ functions.
I tried using EF.Functions but didn't achieve much. My attempt
await _dbContect.Table
.Where(x => !string.IsNullOrEmpty(x.TypeJson ) &&
EF.Functions.JsonContains(x.TypeJson , "[1]")
.ToListAsync();
But it produces error as column is type of text and not Json
System.InvalidOperationException: The EF JSON methods require a JSON parameter and none was found.
The entity:
public class Table
{
public int Id { get; set; }
public string Name { get; set; }
public string TypeJson { get; set; }
}
Using FromSqlRaw() is not possible because there is already written code and would be preferable if I didn't have to rewrite whole code block.
As I found out my code had three main problems
await _dbContect.Table
.Where(x => !string.IsNullOrEmpty(x.TypeJson) &&
EF.Functions.JsonContains(x.TypeJson , "[1]")
.ToListAsync();
First of all I was using EF.Functions.JsonContains() function on
text column which is not valid, json functions are deliberately
written for jsonb type.
After altering column type to jsonb, the
second problem was using string function to check if jsonb column
was null or empty which doesn't make sense and produces exception. Link to github issue
The third problem was the parameter I tried to filter with "[1]", integer needs to be passed as a JsonElement JsonSerializer.SerializeToElement(value); Link to github issue by ahanusa
Credits to #GuruStron for directing me to correct direction

FitNesse / FitSharp - Read columns of ColumnFixture dynamically

I am using the FitNesse / FitSharp (c#) for testing purposes.
I can create normal fixture like ColumnFixtures, RowFixtures, DoFixtures etc. but not I am looking for a way to read columns and bind them dynamically.
The reason for this is, I still already have a huge amount of Pojo objects in my own library and don't want to repeat all class members again. Therefor i am searching for a way to handle column dynamically.
e.g.
!|Create| pojoType | record | pojoName |
|Name | LastName | Address| Misc |
| a | b | c | d |
public class DynamicHandling : DoFixture () {
public void CreateRecord(string type, string name) {
var clazz = GetClazzOfType();
var headers = GetHeadersOfColumn();
var values = GetValuesOfColumn();
var pojo = DoBindingAndAssignValues(headers, rows, clazz);
// ... Continue with whatever e.g. ...
var name = pojo.Name;
var lastName = pojo.LastName;
var address = pojo.Address;
address.split(';') ...
}
}
Any idea ?
Take a look at the source code for the Compute fixture (https://fitsharp.github.io/Fit/ComputeFixture.html) and see if it helps.
You can write a fixture that processes cells dynamically like this:
public class MyFixture: Interpreter {
public void Interpret(CellProcessor processor, Tree<Cell> table) {
new Traverse<Cell>()
.Rows.Header(row => FunctionThatDoesSomethingWithTheHeaderRow(row))
.Rows.Rest(row => FunctionThatDoesSomethingWithEachSubsequentRow(row))
.VisitTable(table);
}
...
}
There's other sets of rows you can traverse - check out the Traverse source code.

Generate Auto-Number with considering Threading & Concurrent Request

So I need to create a feature for generating auto number with +1 increment for each transaction that is saved. So basic requirement is this auto number generated must not be duplicated.
Table being used is
AutoNumber | TransactionInv
---------- | ----------------
Id | Id
Code | TransactionNo
LastNumber |
Example record of table is
AutoNumber
Id | Code | LastNumber
1 | AN-INV | 17
1 | AN-PO | 20
TransactionInv
Id | TransactionNo
1 | 2017-00017
2 | 2017-00018
Current function that I create
public string GetAutoNo(string code, IRepository<AutoNumber, Guid> autoNumberRepository, IUnitOfWorkManager uow)
{
using (var scope = uow.Begin(new UnitOfWorkOptions() { Scope = TransactionScopeOption.Required, IsolationLevel = IsolationLevel.ReadUncommitted }))
{
var autoNumber = autoNumberRepository.Where(c => c.Id == Id && c.Code == code).OrderByDescending(c => c.LastNumber).FirstOrDefault();
if (autoNumber == null)
{
autoNumber = new AutoNumber();
autoNumber.Code = code;
autoNumber.LastNumber = 0;
}
double currentNumber = autoNumber.LastNumber + 1;
var isUsed = autoNumberRepository.FirstOrDefault(c => c.LastNumber == currentNumber);
if (isUsed == null)
{
autoNumber.LastNumber += 1;
autoNumberRepository.Insert(autoNumber);
scope.Complete();
return currentNumber.ToString("00000");
}
else
{
return GetAutoNo(code, autoNumberRepository, uow);
}
}
}
My current problem is when multi user saving the transaction in a milliseconds different then it will be duplicated. Things to be take note that will auto number duplicate :
transaction save processing time
user connection speed when save transaction
many user saving at the same time / many users accessing transaction table
There are solution that I haven't tried yet, which is holdlock / tablelock, but if I have many users I think this solution is not a good idea, that's why I still think whether any better idea for this ?
If you guys have a experience in doing the same thing, maybe can advice me the better approach for this function ? I really appreciate it.
Thanks
You can try to consider using Sequence Number, then use NEXT VALUE every time it is called.
By doing this you can avoid duplicate numbers.

LinqToExcel parsing pivoted data

I've been trying to parse an excel file using the LinqToExcel library. My excel file has the following "design":
Property1 | Property2 | HasExtraProperty1 | HasExtraProperty2 | HasExtraProperty3
------------|---------------|-----------------------|-----------------------|-------------------
foo | bar | yes | yes | no
barfoo | foobar | no | no | yes
barbar | foofoo | no | yes | no
An abstraction of my model looks like this:
class MyModel
{
List<ExtraProperties> extraProperties;
String property1;
String property2;
}
I used the mappings from the library to easily map the (in this example) String properties to the columns. This all works fluently, but now I'm stuck parsing the other properties. Only the the extra properties with a "yes" should be added to the list. Any ideas on how to solve this with a linq query?
Note 1: For future-proofness, the number of extra properties should be able to vary.
Note 2: I've considered using another library, but I'm already using LinqToExcel somewhere in my project, and I'm trying to keep the dependencies at a minimum.
Seems like the easiest solution was to abandon the convenient mapping provided by LinqToExcel, and just looping through every columnname/row.
IExcelQueryFactory fact = new ExcelQueryFactory(path);
var query = from r in fact.Worksheet(0)
select r;
IList<MyModel> models = new List<MyModel>();
foreach(var row in query){
MyModel m = new MyModel();
foreach(String colName in MyColMapping.Keys){
p.GetType().GetProperty(colName).SetValue(p, row[ColMapping[colName]]);
}
foreach(ExtraProperty p in PMapping.Keys){
if(row[PMapping[p]].Equals("yes"))
m.ExtraProperties.Add(p);
}
models.add(m);
}
Note: ColMapping is a dictionary which maps names of excel-columns with model-properties. PMapping is a dictionary which maps excel-columns with the right object of the extra properties.

how to compare current row with the previous row in the same table

How to compare everytime, the current record with the previous record in the same table using MySQL C# in MVC3.0.
This is my table
Historytable:
id | projid| task | name | description | date | type
----|-------| ----- | -------------- |------------ | -------| ---------
1 | 1 | sys21 | validation | validating user | 1-5-12 | created
2 | 1 | sys21 | bug tracking | background bug | 23-7-12 | updated
| | | | tracking | |
3 | 1 | sys21 | bug tracking | bug reporting | 30-8-12 | updated
4 | 1 | sys21 | bugs | bug reporting | 12-9-12 | updated
----------------------------------------------------------------------------------
now i want the result such that compare the record of type updated with the previous record in order to show the previous record as the previous history and record obtained by comparing with the previous record and display only the updated fields as the current history.
now depending upon the projid retrieve the history.
and my view look like the below:
previous history current history
---------------- ---------------
type: created
name: validation
description: validating user
--------------------------------------------------------------
type: created updated
name validation bug tracking
description: validating user background bug tracking
--------------------------------------------------------------------
type: updated updated
name: bug tracking bug report
description: background bug tracking bug reporting
----------------------------------------------------------------
type: updated updated
name: bug tracking -
Description: background bug tracking bug reporting
------------------------------------------------------------------------
type: updated updated
name: bug tracking bugs
Description: bug reporting -
I am expecting the above output, any one plz help me out from the situation,
any king of sugesions will be accepted...
Thankyou,
I am not sure I understood you correctly but you could approach this with the following logic:
Get the rows that represent the history of an item and order by date descending
Get the first row from above as the last change
Get the second row from 1. as the previous to last change
Compare the data
Here's a potential approach for this (using Linq):
var history = db.History.Where(item => item.ProjId == 1)
.OrderByDescending(item => item.Date);
var lastChange = history.First();
var previousChange = history.Skip(1).First();
Now you need to send the above rows to your comparison method. If you want to highlight the changes, you can iterate through properties of the rows and compare values for same properties like this:
private IEnumerable<Tuple<string, object, object>> GetChangesBetweenRows(History row1, History row2)
{
var result = new List<Tuple<string, object, object>>();
var properties = lastChange.GetType().GetProperties(); // both rows are of the same type
foreach(var propInfo in properties)
{
var obj1 = propInfo.GetValue(lastChange, null);
var obj2 = propInfo.GetValue(previousChange, null);
if(obj1 != obj2)
result.Add(Tuple.Create(propInfo.Name, obj1, obj2));
}
return result;
}
EDIT
Given the method above, you can iterate through a collection of history rows and get differences between any of two rows in the collection:
static void Main(string[] args)
{
var history = db.History.Where(item => item.ProjId == 1)
.OrderBy(item => item.Date)
.ToArray();
for(int i=1; i<history.Length; i++)
{
var diff = GetChangesBetweenRows(history[i-1], history[i]);
DisplayDifferences(diff);
}
}
static void DisplayDifferences(IEnumerable<Tuple<string, object, object>> diff)
{
foreach(var tuple in diff)
{
Console.WriteLine("Property: {0}. Object1: {1}, Object2: {2}",tuple.Item1, tuple.Item2, tuple.Item3);
}
}

Categories

Resources