I have a dynamic table in my Web Application (written with angualrjs), in this table you can add columns / add rows and etc..
I want to keep this table/s stored in a database using entity framework.. I save this table to the server as a List[] (Array of List of strings - each List in the array represent a row in the table).
But entity framework requires me to create a model.. but the probelm is the table is completely dynamic.... (users can Add/Remove Rows/Columns dynamicly..)
How can I achieve storing a List[] in a data table with entity
framework?
Thanks alot for the help!!!
Or is there a better way of implementing this?
If you want to model it in terms of EF/DB modelling, you can do 2 things(very basic)
Standard one to many relationship between a row and columns.
One row with id and values column, where the values column is just a comma separated list.
In the example below DynamicData and DynamicDataValue are example of 1-many relationship and DynamicData2 is comma separated list
The EF Context
public class Context : DbContext
{
public Context()
: base("35213027DatatableFromArraylist"){}
public DbSet<DynamicData> DynamicDatas { get; set; }
public DbSet<DynamicData2> DynamicData2s { get; set; }
}
1-many
public class DynamicData
{
public int Id { get; set; }
public virtual ICollection<DynamicDataValue> Values { get; set; }
}
public class DynamicDataValue
{
public int Id { get; set; }
public string Value { get; set; }
}
Comma Seperated
public class DynamicData2
{
public int Id { get; set; }
public string Values { get; set; }
}
Saving and Reading
static void Main(string[] args)
{
//one-many
using (var context = new Context())
{
var values = new List<DynamicDataValue>();
for (int i = 0; i < 11; i++)
{
values.Add(new DynamicDataValue { Value = string.Format("Value{0}", i) });
}
context.DynamicDatas.Add(new DynamicData { Values = values });
context.SaveChanges();
var query =
context.DynamicDatas.Select(
data => new { data.Id, values = data.Values.Select(value => value.Value) }).ToList();
foreach (var item in query)
{
var strings = item.values.Aggregate((s, s1) => string.Format("{0},{1}", s, s1));
Console.WriteLine("{0} - {1}", item.Id, strings);
}
}
Console.ReadLine();
//comma seperated
using (var context = new Context())
{
var values = new List<string> { "value1", "value2", "value3" };
context.DynamicData2s.Add(new DynamicData2 { Values = values.Aggregate((s, s1) => string.Format("{0},{1}", s, s1)) });
context.SaveChanges();
var data = context.DynamicData2s.ToList();
foreach (var dynamicData2 in data)
{
Console.WriteLine("{0}-{1}", dynamicData2.Id, dynamicData2.Values);
}
}
}
Related
I'm starting with Livecharts2 (I did not try previous versions) and I'm not sure how to bind data with Entity Framework.
I need to display a chart with warehouse name and the quantity of access of each.
This is what I already have:
List<Access> access = context.Access.ToList();
var countAccess = access
.GroupBy(acc => acc.IdWarehouse)
.Select(group => new
{
Warehouse = group.Key,
Quantity = group.Count()
});
List<int> listQt = new List<int>();
List<int> list_warehouses = new();
foreach (var item in countAccess)
{
listQt.Add(item.Quantity);
list_warehouses.Add(item.Warehouse);
}
cartesianChart1.Series = new ISeries[]
{
new LineSeries<int>
{
Values = listQt,
Name = "Quantity"
},
new ColumnSeries<int>
{
Values = list_warehouses,
Name = "Warehouse"
}
};
My model classes:
public partial class Access
{
public int IdAccess { get; set; }
public byte IdWarehouse { get; set; }
}
public partial class Warehouse
{
public byte IdWarehouse { get; set; }
public string Name{ get; set; } = null!;
}
This code works with the IdWarehouse but Name, is there a better way to do it, instead of creating new list, foreach etc? I'm not sure if it is unnecessary
I tried with List<string> to get the warehouse's names, but got an exception cause is not implemented yet by creator/s
I have a dataset returning two tables with stored procedure; the first one is in a one-to-one relationship with inner join.
My second table is the items table marked with the id column in the first table.
Table1.ID is kept in Def_SpecificationID column
Stored procedure code:
SELECT Spec.ID as SpecID,
Spec.Def_Specification_GroupID,
Spec.SpecTitle,
Spec.HasItem,
Spec.IsActive,
SpecGroup.SpecGroup
FROM Def_Specification Spec
INNER JOIN Def_Specification_Group SpecGroup ON Spec.Def_Specification_GroupID = SpecGroup.ID
WHERE Spec.IsActive = 1
SELECT ID, Def_SpecificationID, SpecificationTitle
FROM Def_Specification_Items
table structure
What I want to do here is to add data to the elements of the first table according to the Def Specification ID in the second table.
Entity
public class DefSpecificationAndGroupAndItems
{
public DefSpecificationAndGroupAndItems()
{
this.DefSpecificationItems = new();
}
public int ID { get; set; }
public int Def_Specification_GroupID { get; set; }
public string SpecTitle { get; set; }
public int HasItem { get; set; }
public bool IsActive { get; set; }
public string SpecGroup { get; set; }
public List<DefSpecificationItems> DefSpecificationItems { get; set; }
}
Dapper code
await connection.QueryAsync<DefSpecificationAndGroupAndItems,DefSpecificationItems, DefSpecificationAndGroupAndItems>(
"SP_DEF_SPECIFICATION_GET_ALL_BY_ACTIVE",
(spec,items)=> {
DefSpecificationAndGroupAndItems result=new();
result.DefSpecificationItems.Add(items);
return result;
},
new { Active = active },
commandType: CommandType.StoredProcedure,
splitOn: "Def_SpecificationID,SpecID"
);
This code worked for me but is there a dapper version of it
var specification = new List<DefSpecificationAndGroupAndItems>();
using (var multi = await connection.QueryMultipleAsync("SP_DEF_SPECIFICATION_GET_ALL_BY_ACTIVE", new { Active = active },
commandType:CommandType.StoredProcedure))
{
var specs =(await multi.ReadAsync<DefSpecificationAndGroupAndItems>()).ToList();
var specItems = (await multi.ReadAsync<DefSpecificationItems>()).ToList();
foreach (var item in specs)
{
item.DefSpecificationItems = specItems.Where(i => i.Def_SpecificationID == item.ID).ToList();
}
specification = specs;
}
How can I map tables returned from dataset in dapper?
You can just use:
SELECT *
FROM Def_Specification_Items
WHERE Def_SpecificationId = #DefSpecificationId;
#DefSpecificationId will be parameter passed to Dapper:
specs.DefSpecificationItems = await connection
.QueryAsync<List<DefSpecificationItems>>(sql, new
{
DefSpecificationId = specs.Id
});
specs is DefSpecificationAndGroupAndItems here
So I'm passing in a list of objects (that are originally in the database already) to a function to update a property (SentDate) in the database, the structure is similar to
public class Product
{
[Key, Column("SKU", Order = 0)]
public string SKU { get; set; }
[Key, Column("Sequence", Order = 1)]
public int Sequence { get; set; }
public DateTime SentDate { get; set; }
}
And it is going into a function to update. Where I went wrong was I was attempting to do:
public static void UpdateSentDate(List<Product> records, DateTime CurrentDate)
{
DbContext db = new DbContext(); // there is a DbSet for Product in here
var toUpdate = db.Products.Where(c => records.Contains(c)).ToList();
foreach (var rec in toUpdate)
{
rec.SentDate = CurrentDate;
}
db.SaveChanges();
}
This bombs at the toUpdate creation due to the records.Contains(c) as it doesn't involve primitives. So I'm curious how to get the records where records's SKUs and Sequences match up with the database's that is better than my current stopgap:
List<Product> dbRecords = new List<Product>();
foreach (var record in records)
{
var item = db.Products.Where(c => c.SKU == record.SKU && c.Sequence == record.Sequence).Single();
dbRecords.Add(item);
}
you can make it work a little faster if you assign a new date in the same time
foreach (var record in records)
{
var item = db.Products.Where(c => c.SKU == record.SKU && c.Sequence == record.Sequence).Single();
if (item!=null)
{
item.SentDate = CurrentDate;
db.Entry(item).Property(i=>i.SentDate).IsModified = true; // maybe you can ommit this
}
}
db.SaveChanges();
I have TextBox where users can input many numbers (1 per line).
Then, I'm querying a Child Table which has those numbers.
Those numbers are ForeignKeys from Primary Table.
Primary Table - tblOrders
Child Table - tblOrderItems (ForeignKey is OrderID)
public class OrderItems
{
public int ID { get; set; }
public string Order { get; set; }
public string Status { get; set; }
public DateTime DataC { get; set; }
public int Item { get; set; }
}
public IEnumerable<OrderItems> LoadItems()
{
List<OrderItems> list = new List<OrderItems>();
string[] textArray = TxtOrder.Text.Split(new string[] { ronment.NewLine }, StringSplitOptions.None);
foreach (var text in textArray.Distinct())
{
var ctx = new DbContext();
var query = (from p in ctx.tblOrderItems.AsQueryable()
join m in ctx.tblOrders on p.RegistID equals m.RegistID
where m.Order.Contains(text)
select new OrderItems
{
ID = p.RegistTID,
Order = m.Order,
Status = p.Status,
DataC = m.DataC,
Item = p.Item
}).FirstOrDefault();
list.Add(query);
}
return list;
}
The problem: Querying like this in the Primary Key, I get correct values because I only get 1 record per item added in TxtOrder Textbox.
But I'm querying tblOrderItems and the tblOrderItems has many records related to 1 record in tblOrders and I can't get them all to my DataGridView.
To get the items instead of the item, you need to:
Use ToList instead of FirstOrDefault and AddRange instead of Add.
I have a json structure like this:
public class MyModel
{
public int Id { get; set; }
public List<Tables> Tables { get; set; }
}
public class Tables
{
public string Name { get; set; }
public string[] Columns { get; set; }
}
This is how I am creating this structure:
var Ids = new List<int>();
Ids.Add(100);
Ids.Add(101);
Ids.Add(102);
var list = new List<MyModel>();
foreach (var item in Ids)
{
list.Add(
new MyModel
{
Id = item,
Tables = GetTables()
}
);
}
public List<Tables> GetTables()
{
from table in connection.GetSchema("Tables").AsEnumerable()
let name = (string)table["TABLE_NAME"]
let catalog = (string)table["TABLE_CATALOG"]
let schema = (string)table["TABLE_SCHEMA"]
select new Tables
Name = name,
Columns =
from column in connection.GetSchema("Columns", new [] { catalog, schema, name }).AsEnumerable()
select (string)column["COLUMN_NAME"]).ToArray()
}).ToList();
It is possible to have data like this :
[101] : List of tables
[102] : List of tables
[103] : List of tables
Right now i am doing this on client side(ie in javascript) like below:
var list = [];
for (var i = 0; i < response.length; i++) {
list[response.Id] = { tables: response[i].tables };
}
So can i create same response like above on server side?
You can create using Dictionary.
public class RootObject
{
public Dictionary<int, List<Tables>> MyModel { get; set; }
}
You have to pass id as a key and list of tables as a value.
You can use hash table.after getting your data for list variable.then looping the your list variable and add to hash table.
Hashtable hashtable = new Hashtable();
foreach (MyModel myItem in yourlistvariable)
{
if (!hashtable.ContainsKey(myItem.Id))
{
hashtable[myItem.Id] = myItem.Tables;
}
}
finally in hashtable variable you have data how you want