How to design nested class properly? - c#

I generate 2 class looked like this :
public class mPromotionDetail
{
public long PromotionDetailId { get; set; }
public long PromotionHeaderId { get; set; }
public long PromotionTypeId { get; set; }
public string PromotionTypeName { get; set; }
public string VendorCode { get; set; }
public string VendorName { get; set; }
public bool Active { get; set; }
public List<mPromotionDetailArticle> RequestDetailArticles { get; set; }
public static List<mPromotionDetail> Get(long PromotionDetailId = 0, long PromotionHeaderId = 0, long PromotionTypeId = 0, string VendorCode = "", bool Active = true)
{
try
{
Hashtable htParam = new Hashtable();
htParam.Add("#PromotionDetailId", PromotionDetailId);
htParam.Add("#PromotionHeaderId", PromotionHeaderId);
htParam.Add("#PromotionTypeId", PromotionTypeId);
htParam.Add("#VendorCode", VendorCode);
htParam.Add("#Active", Active);
DataSet ds = DB.ExecuteSP_Ds("udsp_GetPromotionDetail", htParam);
return ds.Tables[0].AsEnumerable().Select(row => new mPromotionDetail
{
PromotionDetailId = row["PromotionDetailId"],
PromotionHeaderId = row["PromotionHeaderId"],
PromotionTypeId = row["PromotionTypeId"],
PromotionTypeName = row["PromotionTypeName"],
VendorCode = row["VendorCode"],
VendorName = row["VendorName"],
Active = row["active"],
RequestDetailArticles = mPromotionDetailArticle.Get(PromotionDetailId: Shared.NtL(row["PromotionDetailId"]), Active: true)
}).ToList();
}
catch (Exception ex)
{
throw ex;
}
}
}
public class mPromotionDetailArticle
{
public long PromotionDetailArticleId { get; set; }
public long PromotionDetailId { get; set; }
public string ArticleCode { get; set; }
public string ArticleDescription { get; set; }
public long Qty { get; set; }
public string UoM { get; set; }
public decimal NormalPrice { get; set; }
public decimal SpecialPrice { get; set; }
public bool Active { get; set; }
public static List<mPromotionDetailArticle> Get(long PromotionDetailArticleId = 0, long PromotionDetailId = 0, long PromotionHeaderId = 0, bool Active = true)
{
try
{
Hashtable htParam = new Hashtable();
htParam.Add("#PromotionDetailArticleId", PromotionDetailArticleId);
htParam.Add("#PromotionDetailId", PromotionDetailId);
htParam.Add("#PromotionHeaderId", PromotionHeaderId);
htParam.Add("#Active", Active);
DataSet ds = DB.ExecuteSP_Ds("udsp_GetPromotionDetailArticle", htParam);
return ds.Tables[0].AsEnumerable().Select(row => new mPromotionDetailArticle
{
PromotionDetailArticleId = row["PromotionDetailArticleId"],
PromotionDetailId = row["PromotionDetailId"],
ArticleCode = row["ArticleCode"],
ArticleDescription = row["ArticleDescription"],
Qty = row["Qty"],
UoM = row["UoM"],
NormalPrice = row["NormalPrice"],
SpecialPrice = row["SpecialPrice"],
Active = row["active"]
}).ToList();
}
catch (Exception ex)
{
throw ex;
}
}
}
Note that ExecuteSP_Ds is just calling my SQL SP and returns DataSet.
This works just fine. But if mPromotionDetail.Get returns many rows (ex: 1000 rows), it means mPromotionDetailArticle.Get will be executed just as much time.
Is there any way to design this more properly and efficiently?
Thank you

You could start by decoupling your database code from your entities, some good, and tested ways to do it are by using some of the following patterns:
DAOs
Repositories
For further research I recommend you to read this article:
MSDN - Persistence Patterns
There it also speaks about Lazy and Eager loading, that way you could minimize the workload and size of your database call.
Finally it be good for you to read about the SOLID Principles, some good places are:
Scotch.io SOLID
Solid Principles Succintly
Solid Using C#

If we are talking hundreds/thousands of rows on your call to these procs, consider having the procs take paging parameters (e.g. pageNumber, rowsPerPage). Then modify your proc to use this paging parameters. You can search in SO about how to apply paging in your queries.
Your other option, is to have your proc return multiple results sets and then just do the object mapping of your master-details data in the code.

Related

Stack overflow on list traversal

I've sourced my data for a treeview using the Proces datastructure below. expanded simply indicates whether or not the tree item has been expanded to show all of its children. This is my attempt to iterate through a map all showing items into a DataTable.
public class Proces
{
public string PN { get; set; }
public string Description { get; set; }
public int Qty { get; set; }
public string PartType { get; set; }
public decimal PricePer { get; set; }
public string Mfr { get; set; }
public int Stock { get; set; }
public int OnOrder { get; set; }
public string parent { get; set; }
public bool expanded { get; set; } = false;
public List<Proces> subProcesses { get; set; }
}
I'm trying to map this out into a DataTable, but i keep getting a stack overflow.
void generateShownTree(List<Proces> proccess)
{
foreach (Proces proc in processes)
{
DataRow drNew = export.NewRow();
drNew["Parent"] = proc.parent;
drNew["PN"] = proc.PN;
drNew["Description"] = proc.Description;
drNew["Qty"] = proc.Qty;
drNew["PartType"] = proc.PartType;
drNew["PricePer"] = proc.PricePer;
drNew["Mfr"] = proc.Mfr;
drNew["Stock"] = proc.Stock;
drNew["OnOrder"] = proc.OnOrder;
export.Rows.Add(drNew);
if (proc.expanded == true)
{
foreach (Proces subProc in proc.subProcesses)
{
subProc.parent = proc.PN;
drNew = export.NewRow();
drNew["Parent"] = subProc.parent;
drNew["PN"] = subProc.PN;
drNew["Description"] = subProc.Description;
drNew["Qty"] = subProc.Qty;
drNew["PartType"] = subProc.PartType;
drNew["PricePer"] = subProc.PricePer;
drNew["Mfr"] = subProc.Mfr;
drNew["Stock"] = subProc.Stock;
drNew["OnOrder"] = subProc.OnOrder;
export.Rows.Add(drNew);
generateShownTree(proc.subProcesses);
}
}
}
}
I assume you don't want to iterate the list of subprocesses as well as invoke the generateShownTree method recursively. I also changed the name of the argument passed to generateShownTree to match the object being iterated.
static void generateShownTree(List<Proces> processes)
{
foreach (Proces proc in processes)
{
DataRow drNew = export.NewRow();
drNew["Parent"] = proc.parent;
drNew["PN"] = proc.PN;
drNew["Description"] = proc.Description;
drNew["Qty"] = proc.Qty;
drNew["PartType"] = proc.PartType;
drNew["PricePer"] = proc.PricePer;
drNew["Mfr"] = proc.Mfr;
drNew["Stock"] = proc.Stock;
drNew["OnOrder"] = proc.OnOrder;
export.Rows.Add(drNew);
if (proc.expanded)
{
generateShownTree(proc.subProcesses);
}
}
}

Import the values stored in the database from the controller

[HttpGet]
public ActionResult Create()
{
Articles article = new Articles();
return View(article);
}
[HttpPost]
public ActionResult Create(Articles article)
{
try
{
article.Family = article.ArticleIDX; //그룹번호
article.Parent = 0; //순서
article.Depth = 1; //그룹내 최상위 글로부터 매겨지는 순서
article.Indent = 0; //들여쓰기
article.ModifyDate = DateTime.Now;
article.ModifyMemberID = User.Identity.Name;
db.Articles.Add(article);
db.SaveChanges();
if (Request.Files.Count > 0)
{
var attachFile = Request.Files[0];
if (attachFile != null && attachFile.ContentLength > 0)
{
var fileName = Path.GetFileName(attachFile.FileName);
var path = Path.Combine(Server.MapPath("~/Upload/"), fileName);
attachFile.SaveAs(path);
ArticleFiles file = new ArticleFiles();
file.ArticleIDX = article.ArticleIDX;
file.FilePath = "/Upload/";
file.FileName = fileName;
file.FileFormat = Path.GetExtension(attachFile.FileName);
file.FileSize = attachFile.ContentLength;
file.UploadDate = DateTime.Now;
db.ArticleFiles.Add(file);
db.SaveChanges();
}
}
ViewBag.Result = "OK";
}
catch (Exception ex)
{
Debug.WriteLine("Board");
Debug.WriteLine(ex.ToString());
ViewBag.Result = "FAIL";
}
return View(article);
//return RedirectToAction("ArticleList");
}
[HttpGet]
public ActionResult ReplyCreate(int aidx)
{
Articles articleReply = new Articles();
return View(articleReply);
}
[HttpPost]
public ActionResult ReplyCreate(Articles replyArticles)
{
Articles articles = new Articles();
try
{
//부모글 불러오기(글번호로 불러오기)
Articles note = db.Articles.Find(articles.ArticleIDX);
//Family는 원글의 번호
replyArticles.Family = replyArticles.ArticleIDX;
//Parent 순서
//Depth 는 답글의 글 번호
//Indent 들여쓰기
replyArticles.ModifyDate = DateTime.Now;
replyArticles.ModifyMemberID = User.Identity.Name;
db.Articles.Add(replyArticles);
db.SaveChanges();
ViewBag.Result = "OK";
}
catch (Exception ex)
{
ViewBag.Result = "FAIL";
}
return View(replyArticles);
}
public partial class Articles
{
[Key]
public int ArticleIDX { get; set; }
public int? Family { get; set; }
public int? Depth { get; set; }
public int? Indent { get; set; }
public int? Parent { get; set; }
[StringLength(200)]
public string Title { get; set; }
[Column(TypeName = "text")]
public string Contents { get; set; }
[StringLength(50)]
public string Category { get; set; }
[StringLength(20)]
public string ModifyMemberID { get; set; }
public DateTime? ModifyDate { get; set; }
public virtual Members Members { get; set; }
}
The above code is the code I implemented.
Articles created using the create method are stored in the database.
What do you do when you try to recall a post stored in the database with ReplyCreate?
The null value is often entered into the model.
I try to find it using the primary key, but the primary key also has a null value.
Articles note = db.Articles.Find(articles.ArticleIDX);
does not work because articles is an empty object, due to the line
Articles articles = new Articles();
just above. You never set any of the fields in this object, including the ArticleIDX, before calling the Find method.
I think you probably intended to search using the value passed in to the controller? In that case it would need to be
Articles note = db.Articles.Find(replyArticles.ArticleIDX);
because replyArticles is the variable which was received from the browser in the request. I assume this contains a value in the ArticleIDX field.
Having said that, I don't know what the purpose of this line of code is, because you never use the note object in any of the following code, so I don't know why you needed to find it.

error when populating list based on class in generic method

I have a list defined as below in each of 11 different classes (which handle web-services)
private List<edbService> genEdbService;
internal class edbService
{
public string ServiceID { get; set; }
public string ServiceName { get; set; }
public string ServiceDescr { get; set; }
public string ServiceInterval { get; set; }
public string ServiceStatus { get; set; }
public string ServiceUrl { get; set; }
public string SourceApplication { get; set; }
public string DestinationApplication { get; set; }
public string Function { get; set; }
public string Version { get; set; }
public string userid { get; set; }
public string credentials { get; set; }
public string orgid { get; set; }
public string orgunit { get; set; }
public string customerid { get; set; }
public string channel { get; set; }
public string ip { get; set; }
}
The list is populated in each class by reading the web-service configuration data from xml files in each class:
public DCSSCustomerCreate_V3_0()
{
try
{
XElement x = XElement.Load(global::EvryCardManagement.Properties.Settings.Default.DataPath + "CustomerCreate.xml");
// Get global settings
IEnumerable<XElement> services = from el in x.Descendants("Service")
select el;
if (services != null)
{
edb_service = new List<edbService>();
// edb_service= Common.populateEDBService("CustomerCreate.xml");
foreach (XElement srv in services)
{
edbService edbSrv = new edbService();
edbSrv.ServiceID = srv.Element("ServiceID").Value;
edbSrv.ServiceName = srv.Element("ServiceName").Value;
edbSrv.ServiceDescr = srv.Element("ServiceDescr").Value;
edbSrv.ServiceInterval = srv.Element("ServiceInterval").Value;
edbSrv.ServiceStatus = srv.Element("ServiceStatus").Value;
edbSrv.ServiceUrl = srv.Element("ServiceUrl").Value;
foreach (XElement ServiceHeader in srv.Elements("ServiceHeader"))
{
...
now what I want to do is have this code in one place in my Common.cs class so I tried:
public static List<edbService> populateEDBService(string xmlDataFile)
{
try
{
XElement x = XElement.Load(global::EvryCardManagement.Properties.Settings.Default.DataPath + xmlDataFile);
// Get global settings
IEnumerable<XElement> services = from el in x.Descendants("Service")
select el;
if (services != null)
{
//edb_Service = new List<edbService>();
foreach (XElement srv in services)
{
edbService edbSrv = new edbService();
edbSrv.ServiceID = srv.Element("ServiceID").Value;
edbSrv.ServiceName = srv.Element("ServiceName").Value;
edbSrv.ServiceDescr = srv.Element("ServiceDescr").Value;
edbSrv.ServiceInterval = srv.Element("ServiceInterval").Value;
edbSrv.ServiceStatus = srv.Element("ServiceStatus").Value;
edbSrv.ServiceUrl = srv.Element("ServiceUrl").Value;
foreach (XElement ServiceHeader in srv.Elements("ServiceHeader"))
{
edbSrv.SourceApplication = ServiceHeader.Element("SourceApplication").Value;
edbSrv.DestinationApplication = ServiceHeader.Element("DestinationApplication").Value;
edbSrv.Function = ServiceHeader.Element("Function").Value;
edbSrv.Version = ServiceHeader.Element("Version").Value;
foreach (XElement ClientContext in ServiceHeader.Elements("ClientContext"))
{
edbSrv.userid = ClientContext.Element("userid").Value;
edbSrv.credentials = ClientContext.Element("credentials").Value;
edbSrv.orgid = ClientContext.Element("orgid").Value;
edbSrv.orgunit = ClientContext.Element("orgunit").Value;
edbSrv.customerid = ClientContext.Element("customerid").Value;
edbSrv.channel = ClientContext.Element("channel").Value;
edbSrv.ip = ClientContext.Element("ip").Value;
}
}
// populateEDBService.Add(edbSrv);
}
}
}
catch (Exception ex)
{
/* Write to log */
Common.logBuilder("CustomerCreate : Form --> CustomerCreate <--", "Exception", Common.ActiveMQ,
ex.Message, "Exception");
/* Send email to support */
emailer.exceptionEmail(ex);
}
return;
}
Now I get a compile error on the return; saying that An object of a type convertible to 'System.Collections.Generic.List<EvryCardManagement.Common.edbService>' is required
and in the class that should call this method, I want to do something like:
edb_service = Common.populateEDBService("CustomerUpdate.xml");
but I get an error Cannot implicitly convert type 'System.Collections.Generic.List<EvryCardManagement.Common.edbService>' to 'System.Collections.Generic.List<EvryCardManagement.CustomerUpdate.edbService>'
So firstly how should I return the list from my generic method and how should I call it to return the list populated with the configuration data?
It sounds like you have your class edbService defined in two namespaces,
EvryCardManagement.Common and
EvryCardManagement.CustomerUpdate
I would suggest defining it in only EvryCardManagement.Common and have everything reference it from there.

How do I extend a model class to another model?

I am trying to extend a class to another class that will collect them as a list.
model:
public class Brand
{
public int BrandId { get; set; }
public string Name { get; set; }
public string Guid { get; set; }
public float Rating { get; set; }
public string Industry { get; set; }
public string Address1 { get; set; }
public string Address2 { get; set; }
public string City { get; set; }
public string State { get; set; }
public string Postal { get; set; }
public string CountryCode { get; set; }
public virtual Snapshot Snapshot { get; set; }
}
public class Snapshot
{
public int ID { get; set; }
public string Guid { get; set; }
public int CompanyID { get; set; }
public string CompanyName { get; set; }
public string Email { get; set; }
public DateTime DateTimeSent { get; set; }
public string Subject { get; set; }
public string Html { get; set; }
public string Image { get; set; }
public string Unsubscribe { get; set; }
}
public class BrandSnaphotViewModel
{
public Brand Brand { get; set; }
public List<Snapshot> SnapshotItems { get; set; }
}
controller:
public ActionResult Index(string brandGuid)
{
BrandSnaphotViewModel viewModel = new BrandSnaphotViewModel();
Brand brand = GetBrand(brandGuid);
viewModel.Brand = brand;
List<Snapshot> snapshot = GetBrandSnapshots(brand.BrandId);
viewModel.SnapshotItems = snapshot;
List<BrandSnaphotViewModel> viewModelList = new List<BrandSnaphotViewModel>();
viewModelList.Add(viewModel);
return View(viewModelList.AsEnumerable());
}
private Brand GetBrand(string brandGuid)
{
Brand brand = new Brand();
string dbConnString = WebConfigurationManager.ConnectionStrings["dbConn"].ConnectionString;
MySqlConnection dbConn = new MySqlConnection(dbConnString);
dbConn.Open();
MySqlCommand dbCmd = new MySqlCommand();
dbCmd.CommandText = "SELECT *, industries.name AS industry_name FROM brands LEFT JOIN industries ON brands.industry_id = industries.industry_id WHERE brand_guid = '" + brandGuid.ToString() + "' AND private = 0 LIMIT 1";
dbCmd.Connection = dbConn;
MySqlDataReader dbResult = dbCmd.ExecuteReader();
if (dbResult.Read())
{
brand.Guid = dbResult["brand_guid"].ToString();
brand.BrandId = Convert.ToInt32(dbResult["brand_id"]);
brand.Industry = dbResult["industry_name"].ToString();
}
dbResult.Close();
dbConn.Close();
return brand;
}
private List<Snapshot> GetBrandSnapshots(int brandId)
{
string dbConnString = WebConfigurationManager.ConnectionStrings["dbConn"].ConnectionString;
MySqlConnection dbConn = new MySqlConnection(dbConnString);
dbConn.Open();
MySqlCommand dbCmd = new MySqlCommand();
dbCmd.CommandText = "SELECT * FROM snapshots WHERE brand_id = " + brandId + " AND archive = 0 ORDER BY date_sent DESC";
dbCmd.Connection = dbConn;
MySqlDataReader dbResult = dbCmd.ExecuteReader();
List<Snapshot> snapshots = new List<Snapshot>();
while (dbResult.Read())
{
snapshots.Add(new Snapshot
{
SnapshotId = Convert.ToInt32(dbResult["snapshot_id"]),
Subject = dbResult["subject"].ToString(),
DateTimeSent = Convert.ToDateTime(dbResult["date_sent"]),
Image = dbResult["image"].ToString(),
Email = dbResult["email"].ToString(),
ContentType = dbResult["content_type"].ToString(),
Type = dbResult["type"].ToString()
});
}
dbResult.Close();
dbConn.Close();
return snapshots;
}
edit
FIXED
The issue was the VIEW was not referencing the ViewModel as an IENumerable<>. FACEPALM.
#model IEnumerable<projectvia.ViewModels.BrandSnaphotViewModel>
#{
ViewBag.Title = "Index";
}
#foreach(var item in Model)
{
#item.Brand.Guid;
for(int i = 0; i< #item.SnapshotItems.Count; i++)
{
#item.SnapshotItems[i].Subject<br/>
}
}
That resolved the issue.
Thank you both experts for the insights... i took both advice and came to this solution.
you are doing wrong, it is a list.
you cannot add element this way. Create object and add that object in list by calling Add()
do like this to add items in it:
List<BrandEmailList> brandSnapshotsList = new List<BrandEmailList>();
while (dbResult.Read())
{
BrandEmailList brandSnapshots = new BrandEmailList (); // create an object
brandSnapshots.ID = Convert.ToInt32(dbResult["snapshot_id"]);
brandSnapshots.Guid = dbResult["snapshot_guid"].ToString();
brandSnapshots.DateTimeSent = dbResult["date_sent"];
brandSnapshots.Subject = dbResult["subject"].ToString();
brandSnapshots.Image = dbResult["image"];
brandSnapshotsList.Add(brandSnapshots); // add it in list
}
EDIT:
List is a generic thing, you don't need to create a class for it. you can just instantiate a list and add items in it.
why are you doing like that you can do it this way simply:
List<Snapshot> brandSnapshotsList = new List<Snapshot>();
while (dbResult.Read())
{
Snapshot brandSnapshots = new Snapshot(); // create an object
brandSnapshots.ID = Convert.ToInt32(dbResult["snapshot_id"]);
brandSnapshots.Guid = dbResult["snapshot_guid"].ToString();
brandSnapshots.DateTimeSent = dbResult["date_sent"];
brandSnapshots.Subject = dbResult["subject"].ToString();
brandSnapshots.Image = dbResult["image"];
brandSnapshotsList.Add(brandSnapshots); // add it in list
}
Building on what Ehsan Sajjad did, looking at public IEnumerator<Snapshot> BrandEmails, i believe what you look for looks more like this:
public class Snapshot
{
public int ID { get; set; }
public string Guid { get; set; }
// ...
}
public class BrandEmailList : List<Snapshot>
{
}
You need not even create a new type for your brand email list, you can use List<Snapshot> directly.
public ViewResult Whatever() {
var brand = GetBrand(brandName);
var brandSnapshots = GetBrandSnapshots();
return View(brand, brandSnapshots);
}
private Brand GetBrand(string brandName)
{
try
{
var brand = new Brand();
brand.Name = brandName;
// database stuffs ...
return brand;
}
catch (Exception ex)
{
throw ex;
}
}
private List<Snapshot> GetBrandSnapshots()
{
// ...
// DB stuffs -- that *really* should not be in the controller anyways.
// ...
var snapshots = new List<BrandEmailList>();
while (dbResult.Read())
{
// object initializer syntax
snapshots.Add(new Snapshot {
ID = Convert.ToInt32(dbResult["snapshot_id"]),
Guid = dbResult["snapshot_guid"].ToString(),
DateTimeSent = dbResult["date_sent"],
Subject = dbResult["subject"].ToString(),
Image = dbResult["image"],
});
}
return snapshots
}
As a side note, mixing database access into controller methods can be a bad idea. It does not have to be, but it can be. Generally, fetching data from the database happens at a different "level" than serving a MVC result. MVC controller don't have the "purpose" to talk to a database, that work can/should be delegated to a dedicated type. Compare the single responsibility principle part of the SOLID principles.

Codefirst degrades over time

The program below is a socket program that receives data at a pretty fast pace. It runs fine with the CodeFirst section disabled. If I enable it, the program starts out fine but then degrades slowly to the point where nothing appears to be written to the SQL EXPRESS 2012 db. I check this by running the SQL statement below which just selects the last five rows n SQL Management Studio 2012.
Is there something that I am doing wrong?
select * from [MarketDataEntities]
where MarketDataEntities.MarketDataEntityID not in (
select top (
(select count(*) from [MarketDataEntities]) - 5
) MarketDataEntities.MarketDataEntityID
from [MarketDataEntities]
)
using (var dbTDC = new TickDataTestContext())
{
var tde = new SymbolTickDataEntity { Symbol = symbol };
if (!dbTDC.SymbolTickDataDbSet.Any(a => a.Symbol.Equals(symbol)))
{
dbTDC.SymbolTickDataDbSet.Add(tde);
dbTDC.SaveChanges();
}
var mdde = new MarketDataDepthEntity();
dbTDC.MarketDataDepthDbSet.Add(mdde);
dbTDC.SaveChanges();
while (true)
{
// Wait for next request from client
int len = socket.Receive(zmq_buffer);
if (len < 1)
{
Console.WriteLine("Len < 1");
continue;
}
//Console.WriteLine("Got quote");
count++;
// Copy the bytes
byte[] bytes = new byte[len];
Buffer.BlockCopy(zmq_buffer, 0, bytes, 0, len);
MarketDataDepth mdd = MarketDataDepth.CreateBuilder().MergeFrom(bytes).Build();
PrintMarketDataDepth(mdd);
#if false
for (int i = 0; i < mdd.MdCount; i++)
{
MarketData md = mdd.MdList[i];
string timestamp = md.Time;
int index = timestamp.IndexOf(",");
if(-1 != index)
timestamp = timestamp.Remove(index);
DateTime parseResult;
if (false == System.DateTime.TryParseExact(timestamp, format, provider, DateTimeStyles.None, out parseResult))
continue;
var mde = new MarketDataEntity
{
NMDDTag = (long)mdd.NMDDTag,
QType = (0 == md.QuoteType ? QuoteType.Bid : QuoteType.Ask),
QPrice = md.Price,
QSize = md.Size,
QSource = md.Source,
QLiquidityTag = md.ID,
QSilo = md.Silo,
QTimeStamp = parseResult
};
dbTDC.MarketDataDbSet.Add(mde);
mdde.Depth.Add(mde);
}
if (0 == count % 500)
dbTDC.SaveChanges();
#endif
}
}
}
catch (DbEntityValidationException e)
{
foreach (var eve in e.EntityValidationErrors)
{
Console.WriteLine("Entity of type \"{0}\" in state \"{1}\" has the following validation errors:",
eve.Entry.Entity.GetType().Name, eve.Entry.State);
foreach (var ve in eve.ValidationErrors)
{
Console.WriteLine("- Property: \"{0}\", Error: \"{1}\"",
ve.PropertyName, ve.ErrorMessage);
}
}
throw;
}
}
}
public enum QuoteType { Bid = 0, Ask }
public class MarketDataEntity
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int MarketDataEntityID { get; set; }
public long NMDDTag { get; set; }
public QuoteType QType { get; set; }
public double QPrice { get; set; }
public double QSize { get; set; }
public string QSource { get; set; }
public string QLiquidityTag { get; set; }
public string QSilo { get; set;}
[Column("timestamp", TypeName = "datetime2")]
public DateTime QTimeStamp { get; set; }
}
public class MarketDataDepthEntity
{
public int MarketDataDepthEntityID { get; set; }
public virtual IList<MarketDataEntity> Depth { get; set; }
[Column("timestamp", TypeName = "datetime2")]
public DateTime TimeStamp { get; set; }
public MarketDataDepthEntity() { Depth = new List<MarketDataEntity>(); }
}
public class SymbolTickDataEntity
{
public int SymbolTickDataEntityID { get; set; }
[Key]
[Required]
public string Symbol { get; set; }
public virtual IList<MarketDataDepthEntity> Mdds { get; set; }
public SymbolTickDataEntity() { Mdds = new List<MarketDataDepthEntity>(); }
}
public class TickDataTestContext : DbContext
{
public DbSet<MarketDataEntity> MarketDataDbSet { get; set; }
public DbSet<MarketDataDepthEntity> MarketDataDepthDbSet { get; set; }
public DbSet<SymbolTickDataEntity> SymbolTickDataDbSet { get; set; }
}
From your code looks like you are keeping around the TickDataTestContext for the lifetime of your application. So as you keep adding data the local cache keeps increasing increasing memory usage hence performance degradation.
You should rewrite the code to create a new instance of TickDataTestContext for each request that needs to be saved then do the work, save changes and dispose the context.

Categories