Consider very simple database table:
CREATE TABLE UkTest(
id int NOT NULL,
uk int NOT NULL
)
Primary Key on id
Unique Key on uk
Then add 2 rows:
INSERT INTO UkTest (id,uk) VALUES(1,1);
INSERT INTO UkTest (id,uk) VALUES(2,2);
Then do 2 tests.
OK:
var db = new Database1Entities();
var element1 = db.UkTest.FirstOrDefault(e => e.id == 1);
var element2 = db.UkTest.FirstOrDefault(e => e.id == 2);
element1.uk = 0;
element2.uk = 1; // overrides previous element1.uk value
var count = db.SaveChanges();
Fails (before test revert uk values to 1 and 2!):
var db = new Database1Entities();
var element1 = db.UkTest.FirstOrDefault(e => e.id == 1);
var element2 = db.UkTest.FirstOrDefault(e => e.id == 2);
element2.uk = 0;
element1.uk = 2; // overrides previous element2.uk value
var count = db.SaveChanges();
// Cannot insert duplicate key row in object 'dbo.UkTest' with unique index 'UK_UkTest'
See that ObjectContext.SaveChanges() checks rows in the order of primary index.
Is there any way to force own order?
Unless you call SaveChanges() twice, no, there is no way to control the order of SQL statements Entity Framework will send to the database. You could wrap the multiple SaveChanges() calls into an outer transaction to ensure still a transactional behaviour for the whole operation:
using (var scope = new TransactionScope())
{
using (var db = new Database1Entities())
{
var element1 = db.UkTest.FirstOrDefault(e => e.id == 1);
var element2 = db.UkTest.FirstOrDefault(e => e.id == 2);
element2.uk = 0;
db.SaveChanges();
element1.uk = 2;
db.SaveChanges();
}
scope.Complete();
}
Thanks to Slauma. I've found the solution. The key is to keep elements in several ObjectContext instances.
public class SavingElementsWithTransactionInOwnOrder
{
public void SaveElements ()
{
var db = new Database1Entities();
var element1 = db.UkTest.FirstOrDefault(e => e.id == 1);
element1.db = db;
db = new Database1Entities();
var element2 = db.UkTest.FirstOrDefault(e => e.id == 2);
element2.db = db;
element2.uk = 0;
element1.uk = 2;
var scope = new TransactionScope();
try{
element2.db.SaveChanges();
element1.db.SaveChanges();
scope.Complete();
}
finally{
scope.Dispose();
}
}
}
public partial class UkTest
{
public Database1Entities db { get; set; }
}
Related
I am trying to test my ViewComponent with XUnit.
When I debug through the component and set a break point right before it returns the Component View, the model is set.
Here is the simple model I am returning.
public class IntDashMakeRecAssgnmntsPoRespMngrVM
{
public IEnumerable<Audit> Audits { get; set; }
}
And I am trying to assert the Audits.Count() is greater than 0.
Here is my View Component:
public class IntDashMakeRecAssgnmntsPoRespMngrViewComponent : ViewComponent
{
private IAuditRepository _auditRepo;
private IExternalRepository _externalRepo;
public IntDashMakeRecAssgnmntsPoRespMngrViewComponent(IAuditRepository auditRepo,
IExternalRepository externalRepo)
{
_auditRepo = auditRepo;
_externalRepo = externalRepo;
}
public IViewComponentResult Invoke()
{
ClaimsPrincipal user = HttpContext.Request.HttpContext.User;
short staffId = short.Parse(user.Claims.Single(c => c.Type == "StaffId").Value);
// Get all Internal Audits that are not closed and not completed
var audits = _auditRepo.Audits
.Include(a => a.Findings).ThenInclude(f => f.Recommendations).ThenInclude(r => r.Assignments)
.Where(a => a.StatusID != 3 && a.StatusID != 11);
var external = _externalRepo.ExternalRecords;
audits = audits.Where(a => !external.Any(e => e.AuditID == a.AuditID));
if (User.IsInRole("PAG_SPEC") && !User.IsInRole("PAG_ADMIN_INT"))
{
audits = audits.Where(a =>
a.Assignments.Any(assn => assn.AssignmentAuditId == a.AuditID
&& assn.AssignmentRoleId == 2 && assn.AssignmentStaffId == staffId));
}
// Where audit has a recommendation without an assigned PO Authorizer
// OR without an assigned Responsible Manager (Rec Level).
List<Audit> auditsToAssign = new List<Audit>();
foreach (Audit audit in audits)
{
foreach (Finding finding in audit.Findings)
{
foreach (Recommendation rec in finding.Recommendations)
{
if (!rec.Assignments.Any(asgn => asgn.AssignmentRoleId == 15)
|| !rec.Assignments.Any(asgn => asgn.AssignmentRoleId == 26)
)
{
auditsToAssign.Add(rec.Finding.Audit);
break;
}
}
}
}
IntDashMakeRecAssgnmntsPoRespMngrVM intDashMakeRecAssgnmntsPoRespMngrVM =
new IntDashMakeRecAssgnmntsPoRespMngrVM
{
Audits = auditsToAssign
};
return View("/Views/InternalAudit/Components/Dashboard/IntDashMakeRecAssgnmntsPoRespMngr/Default.cshtml", intDashMakeRecAssgnmntsPoRespMngrVM);
}
}
When I get to this line in debugging and break to inspect, I have 1 Audit which I want:
return View("/Views/InternalAudit/Components/Dashboard/IntDashMakeRecAssgnmntsPoRespMngr/Default.cshtml", intDashMakeRecAssgnmntsPoRespMngrVM);
Now here is my Unit Test:
[Fact]
public void ReturnsAudit_1Finding_1Rec_1Asgn_PONeeded_RespMnrAssigned()
{
// Arrange
var audits = new Audit[]
{
new Audit { AuditID = 1 }
};
var findings = new Finding[]
{
new Finding{ Audit = audits[0], FindingId = 1 } // 1 Finding
};
var recommendations = new List<Recommendation>()
{
new Recommendation // 1 Rec
{
Finding = findings[0],
Assignments = new List<Assignment>()
{
// PO Authorizor
new Assignment { AssignmentRoleId = 15 }
// No Responsible Manager
}
}
};
audits[0].Findings = findings;
findings[0].Recommendations = recommendations;
Mock<IAuditRepository> mockAuditRepo = new Mock<IAuditRepository>();
mockAuditRepo.Setup(m => m.Audits).Returns(audits.AsQueryable());
Mock<IExternalRepository> mockExternalRepo = new Mock<IExternalRepository>();
mockExternalRepo.Setup(m => m.ExternalRecords).Returns(
new External[0].AsQueryable()
);
// Act
var component = new IntDashMakeRecAssgnmntsPoRespMngrViewComponent(
mockAuditRepo.Object, mockExternalRepo.Object);
component.ViewComponentContext = new ViewComponentContext();
component.ViewComponentContext.ViewContext.HttpContext = TestContext;
var result =
component.Invoke() as IntDashMakeRecAssgnmntsPoRespMngrVM;
int auditCount = (result).Audits.Count();
// Assert
Assert.Equal(1, auditCount);
}
Why is result null on this line?
var result =
component.Invoke() as IntDashMakeRecAssgnmntsPoRespMngrVM;
I also tried this first and it is still null:
ViewComponentResult result =
component.Invoke() as ViewComponentResult;
int auditCount =
((IntDashMakeRecAssgnmntsPoRespMngrVM)result.Model).Audits.Count();
I figured it out.
I wasn't casting the result to the right type.
I had this:
ViewComponentResult result =
component.Invoke() as ViewComponentResult;
int auditCount =
((IntDashMakeRecAssgnmntsPoRespMngrVM)result.Model).Audits.Count();
It should be this:
var result =
component.Invoke() as ViewViewComponentResult;
int auditCount =
((IntDashMakeRecAssgnmntsPoRespMngrVM)result.ViewData.Model).Audits.Count();
ViewViewComponentResult instead of ViewComponentResult.
I have a table named industries. In this my fields are
workfor_id,
workfor_usr_id,
workfor_industry_id.
With the same values of workfor_id, I have different workfor_industry_id's.
foreach (var k in us){
var ind = dbContext.industries.Where(i => i.workfor_id ==
k.id).Select(i => i).FirstOrDefault();
string ind2 = k.industry;
var industryParts = ind2.Split(',');
var o = (industryParts.Length);
for (c = 0; c < o; c++){
ind.workfor_id = Convert.ToInt16(k.id);
ind.workfor_industry_id = Convert.ToInt16(k.industryid); }
}
To update workfor_industry_id field I have implemented inner loop inside the foreach loop to get the values of workfor_industry_id's.here same record is over loading with different workfor_industry_id's.
can you tell me how to implement this.
UPDATED
This update adds a little more error checking and assumes that -1 is never a valid value for industry_id
short GetShort(string value) {
short returnValue;
value = (value ?? string.Empty).Replace("\"",null);
return short.TryParse(value, out returnValue) ? returnValue : (short)-1;
}
foreach (var k in us){
var id=Convert.ToInt16(k.id);
var toRemove=from i in dbContext.industries
where i.workfor_id == k.id
select i;
var toAdd = from x in (k.industry ?? string.Empty).Split(',')
select new Industry {
workfor_id=id,
workfor_industry_id=GetShort(x)
};
dbContext.industries.DeleteAllOnSubmit(toRemove);
dbContext.industries.InsertAllOnSubmit(toAdd.Where(x=>x.workfor_industry_id != -1));
}
dbContext.SubmitChanges();
I have 2 objects (lists loaded from XML) report and database (showed bellow in code) and i should analyse them and mark items with 0, 1, 2, 3 according to some conditions
TransactionResultCode = 0; // SUCCESS (all fields are equivalents: [Id, AccountNumber, Date, Amount])
TransactionResultCode = 1; // Exists in report but Not in database
TransactionResultCode = 2; // Exists in database but Not in report
TransactionResultCode = 3; // Field [Id] are equals but other fields [AccountNumber, Date, Amount] are different.
I'll be happy if somebody could found time to suggest how to optimize some queries.
Bellow is the code:
THANK YOU!!!
//TransactionResultCode = 0 - SUCCESS
//JOIN on all fields
var result0 = from d in database
from r in report
where (d.TransactionId == r.MovementID) &&
(d.TransactionAccountNumber == long.Parse(r.AccountNumber)) &&
(d.TransactionDate == r.MovementDate) &&
(d.TransactionAmount == r.Amount)
orderby d.TransactionId
select new TransactionList()
{
TransactionId = d.TransactionId,
TransactionAccountNumber = d.TransactionAccountNumber,
TransactionDate = d.TransactionDate,
TransactionAmount = d.TransactionAmount,
TransactionResultCode = 0
};
//*******************************************
//JOIN on [Id] field
var joinedList = from d in database
from r in report
where d.TransactionId == r.MovementID
select new TransactionList()
{
TransactionId = d.TransactionId,
TransactionAccountNumber = d.TransactionAccountNumber,
TransactionDate = d.TransactionDate,
TransactionAmount = d.TransactionAmount
};
//Difference report - database
var onlyReportID = report.Select(r => r.MovementID).Except(joinedList.Select(d => d.TransactionId));
//TransactionResultCode = 1 - Not Found in database
var result1 = from o in onlyReportID
from r in report
where (o == r.MovementID)
orderby r.MovementID
select new TransactionList()
{
TransactionId = r.MovementID,
TransactionAccountNumber = long.Parse(r.AccountNumber),
TransactionDate = r.MovementDate,
TransactionAmount = r.Amount,
TransactionResultCode = 1
};
//*******************************************
//Difference database - report
var onlyDatabaseID = database.Select(d => d.TransactionId).Except(joinedList.Select(d => d.TransactionId));
//TransactionResultCode = 2 - Not Found in report
var result2 = from o in onlyDatabaseID
from d in database
where (o == d.TransactionId)
orderby d.TransactionId
select new TransactionList()
{
TransactionId = d.TransactionId,
TransactionAccountNumber = d.TransactionAccountNumber,
TransactionDate = d.TransactionDate,
TransactionAmount = d.TransactionAmount,
TransactionResultCode = 2
};
//*******************************************
var qwe = joinedList.Select(j => j.TransactionId).Except(result0.Select(r => r.TransactionId));
//TransactionResultCode = 3 - Transaction Results are different (Amount, AccountNumber, Date, )
var result3 = from j in joinedList
from q in qwe
where j.TransactionId == q
select new TransactionList()
{
TransactionId = j.TransactionId,
TransactionAccountNumber = j.TransactionAccountNumber,
TransactionDate = j.TransactionDate,
TransactionAmount = j.TransactionAmount,
TransactionResultCode = 3
};
you may try something like below:
public void Test()
{
var report = new[] {new Item(1, "foo", "boo"), new Item(2, "foo2", "boo2"), new Item(3, "foo3", "boo3")};
var dataBase = new[] {new Item(1, "foo", "boo"), new Item(2, "foo22", "boo2"), new Item(4, "txt", "rt")};
Func<Item, bool> inBothLists = (i) => report.Contains(i) && dataBase.Contains(i);
Func<IEnumerable<Item>, Item, bool> containsWithID = (e, i) => e.Select(_ => _.ID).Contains(i.ID);
Func<Item, int> getCode = i =>
{
if (inBothLists(i))
{
return 0;
}
if(containsWithID(report, i) && containsWithID(dataBase, i))
{
return 3;
}
if (report.Contains(i))
{
return 2;
}
else return 1;
};
var result = (from item in dataBase.Union(report) select new {Code = getCode(item), Item = item}).Distinct();
}
public class Item
{
// You need also to override Equals() and GetHashCode().. I omitted them to save space
public Item(int id, string text1, string text2)
{
ID = id;
Text1 = text1;
Text2 = text2;
}
public int ID { get; set; }
public string Text1 { get; set; }
public string Text2 { get; set; }
}
Note that you need to either implement Equals() for you items, or implement an IEqualityComparer<> and feed it to Contains() methods.
I did a profile tracing to check what functions are taking long times , One of the method takes near 1 second and is called 10+ times and i guess it should be a candidate for review. I have included the method, Can anyone tell me how can it possible be improved.
[NonAction]
private ProductModel.ProductMiscModel PrepareProductMiscModel(Product product)
{
if (product == null)
throw new ArgumentNullException("product");
var model = new ProductModel.ProductMiscModel();
var productVariants = _productService.GetProductVariantsByProductId(product.Id);
var getManufactureImage = _manufacturerService.GetProductManufacturersByProductId(product.Id)
.Select(x =>
{
var m = x.Manufacturer.ToModel();
m.PictureModel.ImageUrl = _pictureService.GetPictureUrl(x.Manufacturer.PictureId, _mediaSetting.ManufacturerThumbPictureSize, true);
m.PictureModel.Title = string.Format(_localizationService.GetResource("Media.Manufacturer.ImageLinkTitleFormat"), m.Name);
m.PictureModel.AlternateText = string.Format(_localizationService.GetResource("Media.Manufacturer.ImageAlternateTextFormat"), m.Name);
return m;
})
.ToList();
model.manufactureName = getManufactureImage;
switch (productVariants.Count)
{
case 0:
{
//var productVariant = productVariants[0];
model.Sku = null;
model.ShowSku = false;
// model.attributeName = 0;
} break;
case 1:
//only one variant
{ var productVariant = productVariants[0];
model.Sku = productVariant.Sku; //null;
model.ShowSku = true;
// model.attributeName = _productAttributeService.GetProductVariantAttributesByProductVariantId(productVariant.Id);
model.productSpecification = _specificationAttributeService.GetProductSpecificationAttributesByProductId(productVariant.Product.Id);
}
break;
}
return model;
}
_manufactureService.GetProductManufactureByProductId
public virtual IList<ProductManufacturer> GetProductManufacturersByProductId(int productId, bool showHidden = false)
{
if (productId == 0)
return new List<ProductManufacturer>();
string key = string.Format(PRODUCTMANUFACTURERS_ALLBYPRODUCTID_KEY, showHidden, productId);
return _cacheManager.Get(key, () =>
{
var query = from pm in _productManufacturerRepository.Table
join m in _manufacturerRepository.Table on
pm.ManufacturerId equals m.Id
where pm.ProductId == productId &&
!m.Deleted &&
(showHidden || m.Published)
orderby pm.DisplayOrder
select pm;
var productManufacturers = query.ToList();
return productManufacturers;
});
}
Use StopWatch in the method to determine which part it is that takes long time.
you might want to include the picture url in the original list instead of traversing each item and call _pictureService.GetPictureUrl.
How can I update a record against specific id in LINQ to SQL?
LINQ is a query tool (Q = Query) - so there is no magic LINQ way to update just the single row, except through the (object-oriented) data-context (in the case of LINQ-to-SQL). To update data, you need to fetch it out, update the record, and submit the changes:
using(var ctx = new FooContext()) {
var obj = ctx.Bars.Single(x=>x.Id == id);
obj.SomeProp = 123;
ctx.SubmitChanges();
}
Or write an SP that does the same in TSQL, and expose the SP through the data-context:
using(var ctx = new FooContext()) {
ctx.UpdateBar(id, 123);
}
In the absence of more detailed info:
using(var dbContext = new dbDataContext())
{
var data = dbContext.SomeTable.SingleOrDefault(row => row.id == requiredId);
if(data != null)
{
data.SomeField = newValue;
}
dbContext.SubmitChanges();
}
AdventureWorksDataContext db = new AdventureWorksDataContext();
db.Log = Console.Out;
// Get hte first customer record
Customer c = from cust in db.Customers select cust where id = 5;
Console.WriteLine(c.CustomerType);
c.CustomerType = 'I';
db.SubmitChanges(); // Save the changes away
DataClassesDataContext dc = new DataClassesDataContext();
FamilyDetail fd = dc.FamilyDetails.Single(p => p.UserId == 1);
fd.FatherName=txtFatherName.Text;
fd.FatherMobile=txtMobile.Text;
fd.FatherOccupation=txtFatherOccu.Text;
fd.MotherName=txtMotherName.Text;
fd.MotherOccupation=txtMotherOccu.Text;
fd.Phone=txtPhoneNo.Text;
fd.Address=txtAddress.Text;
fd.GuardianName=txtGardianName.Text;
dc.SubmitChanges();
I found a workaround a week ago. You can use direct commands with "ExecuteCommand":
MDataContext dc = new MDataContext();
var flag = (from f in dc.Flags
where f.Code == Code
select f).First();
_refresh = Convert.ToBoolean(flagRefresh.Value);
if (_refresh)
{
dc.ExecuteCommand("update Flags set value = 0 where code = {0}", Code);
}
In the ExecuteCommand statement, you can send the query directly, with the value for the specific record you want to update.
value = 0 --> 0 is the new value for the record;
code = {0} --> is the field where you will send the filter value;
Code --> is the new value for the field;
I hope this reference helps.