I have 2 entity types Buyers and BuyerOrders. Buyer can contain multiple BuyerOrders and list of BuyerOrders can be edited by users. When I want to add some BuyerOrders I call method:
private static void CreateOrdersForBuyer(Buyer buyer, int[] selectedLeadTypes)
{
foreach (var order in selectedLeadTypes.Select(leadTypeId => new BuyerOrder
{
Buyer = buyer,
OfferTypeID = (int) OfferTypes.Referral,
Price = 1,
RegistrationDate = DateTime.Now,
StatusID = (int) BuyerOrderStatus.Pending,
LeadtypeID = leadTypeId,
Profit = 1
}))
{
buyer.BuyerOrders.Add(order);
}
}
And then save the buyer:
GenericRepository.Instance.Save(buyer);
Save method:
public virtual void Save<T>(T value) where T : class
{
//LegalLeadsDataContext.Instance = null;
LegalLeadsDataContext.Instance.GetTable<T>().Attach(value);
LegalLeadsDataContext.Instance.Refresh(RefreshMode.KeepCurrentValues, value);
LegalLeadsDataContext.Instance.SubmitChanges();
}
After that I see no new BuyerOrders in Database. What am I doing wrong?
From the MSDN documentation
KeepCurrentValues: Forces the Refresh method to swap the original value with the values retrieved from the database. No current value is modified.
Whereas the KeepChanges
KeepChanges: Forces the Refresh method to keep the current value that has been changed, but updates the other values with the database values.
Also, the Attach method, use the overload that allows you to specify "as modified".
So in your code, it would appear that possibly you need to change
public virtual void Save<T>(T value) where T : class
{
//LegalLeadsDataContext.Instance = null;
LegalLeadsDataContext.Instance.GetTable<T>().Attach(value, true);
LegalLeadsDataContext.Instance.Refresh(RefreshMode.KeepChanges, value);
LegalLeadsDataContext.Instance.SubmitChanges();
}
Related
Below is my code for entity and a function where I need to map entity TblEmployee from a key value pair.
In foreach loop I am getting values based on keys, what should be the best approach to do it?
public class TblEmployee
{
public int EmployeeId { get; set; }
public string Name { get; set; }
}
public int Create()
{
tblEmployee employee = new tblEmployee();
using (var ctx = new theparkeee_testEntities())
{
foreach (string key in HttpContext.Current.Request.Form.AllKeys)
{
string value = HttpContext.Current.Request.Form[key];
//how to map value from key value pair to entity employee.
}
}
}
You can use System.Reflection to get the Properties of an object by their name with Type.GetProperty(string name). After you got the PropertyInfo, you can use SetValue to assign a value to it.
foreach (string key in HttpContext.Current.Request.Form.AllKeys) {
// note that "value" is a reserved word, do not use it as variable name
string val = HttpContext.Current.Request.Form[key];
var propertyInfo = typeof(TblEmployee).GetProperty(key); // can maybe be moved outside of the loop
if (propertyInfo != null) {
propertyInfo.SetValue(employee, val);
}
}
This will work for string properties. If the property is of another type, you have to find the correct type (again, using reflection) and cast the string value before assigning it.
Note that this is not the correct approach to store data in MVC. You should not work with the Request.Form directly, instead your POST action should accept a ViewModel that can be mapped (e.g. using Automapper) to the DB entity. I.e. let the ASP ModelBinder do its work, instead of reinventing the wheel!
[HttpPost]
public ActionResult Submit(MyViewModel postData) {
var employee = Mapper.Map<TblEmployee>(postData);
_ctx.Employees.Add(employee);
_ctx.SaveChanges();
return new HttpStatusCodeResult((int)HttpStatusCode.OK);
}
Earlier I had a table named ApplicationConfiguration which simply had [Key],[Value] columns to store some config data. This was queried straight away using SQL queries.
Now I intend to make use of Entity Framework (EF) Code First approach to query this table. The specialty of this table is that the table will have only a fixed number of rows in its lifetime. Only the Value column can be updated.
So as per the code first approach, we have to first write our POCO classes with its properties that will be mapped to columns in the underlying table. However, I wish to have a Dictionary<> structure to represent these configuration KV pairs. My concern is, will EF be able to fire update queries against any updation to the the value of a particular pair.
Also since I am using Code First approach, I would want some seed data(i.e the fixed number of rows and its initial content) to the added after the table itself is created on the fly when the application is first executed.
If Dictionary<> cannot be used, please suggest some alternative. Thanks in advance.
Coded this way:
public class ApplicationConfiguration
{
public int Id { get; set; }
public string Key { get; set; }
public int Value { get; set; } // should be string, but I'm lazy
}
class Context : DbContext
{
internal class ContextInitializer : DropCreateDatabaseIfModelChanges<Context>
{
protected override void Seed(Context context)
{
var defaults = new List<ApplicationConfiguration>
{
new ApplicationConfiguration {Key = "Top", Value = 5},
new ApplicationConfiguration {Key = "Bottom", Value = 7},
new ApplicationConfiguration {Key = "Left", Value = 1},
new ApplicationConfiguration {Key = "Right", Value = 3}
};
// foreach (var c in defaults)
// context.ConfigurationMap.Add(c.Key, c); // by design, no IReadOnlyDictionary.Add
foreach (var c in defaults)
context.ApplicationConfigurations.Add(c);
base.Seed(context);
}
}
public Context()
{
Database.SetInitializer(new ContextInitializer());
}
private IDbSet<ApplicationConfiguration> ApplicationConfigurations
{
get { return Set<ApplicationConfiguration>(); }
}
public IReadOnlyDictionary<string, ApplicationConfiguration> ConfigurationMap
{
get { return ApplicationConfigurations.ToDictionary(kvp => kvp.Key, kvp => kvp); }
}
}
Used this way:
using (var context = new Context())
{
ReadConfigurationOnly(context.ConfigurationMap);
}
using (var context = new Context())
{
ModifyConfiguration(context.ConfigurationMap);
context.SaveChanges();
}
static void ReadConfigurationOnly(IReadOnlyDictionary<string, ApplicationConfiguration> configuration)
{
foreach (var k in configuration.Keys)
Console.WriteLine("{0} = {1}", k, configuration[k].Value);
}
static void ModifyConfiguration(IReadOnlyDictionary<string, ApplicationConfiguration> configuration)
{
foreach (var k in configuration.Keys)
configuration[k].Value++; // this is why I was lazy, using an int for a string
}
So, I wrote it up this way — using an int Value property rather than a string — just so I could run the "Used this way" code over and over, and see the database update each time, without having to come up with some other way to change Value in an interesting way.
It's not quite as nifty here to use a IReadOnlyDictionary<string, ApplicatonConfiguration> instead of a IReadOnlyDictionary<string, string>, the way we'd really like, but that's more than made up for by the fact that we can easily modify our collection values without resorting to a clumsier Set method taking a dictionary as input. The drawback, of course, is that we have to settle for configuration[key].Value = "new value" rather than configuration[key] = "new value", but — as I say — I think it's worth it.
EDIT
Dang! I wrote this code up specifically to answer this question, but I think I like it so much, I'm going to add it to my bag of tricks ... this would fit in really well when my company goes from local databases to Azure instances in the cloud, and the current app.config has to go into the database.
Now all I need is a ContextInitializer taking a System.Configuration.ConfigurationManager as a ctor parameter in order to seed a new database from an existing app.config ...
I don't think you can map a table directly to a Dictionary; you will probably have to write your own wrapper to fill a dictionary from the table and update it back to the DB. Entities are each a row of a given table... Something like this (untested):
public Dictionary<string, string> GetDictionary()
{
Dictionary<string, string> dic = new Dictionary<string, string>();
using (var db = new Context())
{
var configs = db.ApplicationConfiguration.Select();
foreach (var entry in configs)
{
dic.Add(config.Key, config.Value);
}
}
return dic;
}
public void SaveConfig(Dictionary<string, string> dic)
{
using (var db = new Context())
{
foreach (KeyValuePair kvp in dic)
{
if (!db.ApplicationConfiguration.First(a => a.Key == kvp.Key).Value == kvp.Value)
{
var ac = new ApplicationConfiguration();
ac.Key = kvp.Key;
ac.Value = kvp.Value;
db.Entry(ac).State = EntityState.Modified;
}
}
db.SaveChanges();
}
}
For your second question, you want to use the Seed() method to add initial values to the database. See here for an example implementation.
I am pretty new to SFDC. I am trying to implement a clone functionality of a custom object by which when I am cloning an object, the object as well as all the object in its related list are to be cloned. I have implemented the part of cloning a object but stuck how to get the object list associated with a object's related list. pls let me know , how to implement this.
Thanks
You can try this...
public class PurchaseOrderCloneWithItemsController {
//added an instance varaible for the standard controller
private ApexPages.StandardController controller {get; set;}
// add the instance for the variables being passed by id on the url
private Purchase_Order__c po {get;set;}
// set the id of the record that is created -- ONLY USED BY THE TEST CLASS
public ID newRecordId {get;set;}
// initialize the controller
public PurchaseOrderCloneWithItemsController(ApexPages.StandardController controller) {
//initialize the stanrdard controller
this.controller = controller;
// load the current record
po = (Purchase_Order__c)controller.getRecord();
}
// method called from the VF's action attribute to clone the po
public PageReference cloneWithItems() {
// setup the save point for rollback
Savepoint sp = Database.setSavepoint();
Purchase_Order__c newPO;
try {
//copy the purchase order - ONLY INCLUDE THE FIELDS YOU WANT TO CLONE
po = [select Id, Name, Ship_To__c, PO_Number__c, Supplier__c, Supplier_Contact__c, Date_Needed__c, Status__c, Type_of_Purchase__c, Terms__c, Shipping__c, Discount__c from Purchase_Order__c where id = :po.id];
newPO = po.clone(false);
insert newPO;
// set the id of the new po created for testing
newRecordId = newPO.id;
// copy over the line items - ONLY INCLUDE THE FIELDS YOU WANT TO CLONE
List<Purchased_Item__c> items = new List<Purchased_Item__c>();
for (Purchased_Item__c pi : [Select p.Id, p.Unit_Price__c, p.Quantity__c, p.Memo__c, p.Description__c From Purchased_Item__c p where Purchase_Order__c = :po.id]) {
Purchased_Item__c newPI = pi.clone(false);
newPI.Purchase_Order__c = newPO.id;
items.add(newPI);
}
insert items;
} catch (Exception e){
// roll everything back in case of error
Database.rollback(sp);
ApexPages.addMessages(e);
return null;
}
return new PageReference('/'+newPO.id+'/e?retURL=%2F'+newPO.id);
}
Sounds like you need to "Deep Clone" - check out the links below for reference:
https://salesforce.stackexchange.com/questions/8493/deep-clone-parent-child-grand-child
http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_System_List_deepClone.htm
Peeps,
Im a born again virgin to Silverlight so please bear with me. I have two seperate DomainServices, pointing to two different SQL Database Servers. Within these Domain Services I have setup some IQueryables in each Domain Service.
I need to merge two IQueryables together from seperate DomainServices. Im sure this has got to be do-able.
Below are the two domain services.
I want to merge GetCustomCallLogs (from HEATLiveDomainService) together with GetTblCallsLogged (from HeatDomainService). The key in GetCustomCallLogs would be the CallID and the key in GetTblCallsLogged would be the RecID.
If its possible to do i understand i would need to create a new type to take into account any fields from the two joined tables.
Hopefully ive explained my scenario, and im not being dumb.
Thanks in advance
public class HEATLIVEDomainService : LinqToEntitiesDomainService<HeatIT9_LiveEntities>
{
// TODO:
// Consider constraining the results of your query method. If you need additional input you can
// add parameters to this method or create additional query methods with different names.
// To support paging you will need to add ordering to the 'Assignees' query.
public IQueryable<Assignee> GetAssignees()
{
return this.ObjectContext.Assignees;
}
// TODO:
// Consider constraining the results of your query method. If you need additional input you can
// add parameters to this method or create additional query methods with different names.
// To support paging you will need to add ordering to the 'CallLogs' query.
public IQueryable<CallLog> GetCallLogs()
{
// return this.ObjectContext.CallLogs.Where(c => DateTime.Parse(c.ClosedDate).Year == 2012 && c.CallStatus == "Closed" && c.ClosedBy.Length > 0);
return this.ObjectContext.CallLogs.Where(c => c.CallStatus == "Closed" && c.ClosedDate.Substring(0, 4).Equals("2013"));
}
public IQueryable<CallLog> GetCallLogsLastThisYear()
{
return this.ObjectContext.CallLogs.Where(c => c.CallStatus == "Closed" && (c.ClosedDate.Substring(0, 4).Equals("2012") || c.ClosedDate.Substring(0, 4).Equals("2013")));
}
public IQueryable<CustomCallLog> GetCustomCallLogs(string year)
{
var result = from i in this.ObjectContext.CallLogs
join p in this.ObjectContext.Assignees on i.ClosedBy equals p.LoginID
where i.CallStatus == "Closed" && i.ClosedDate.Substring(0, 4) == year
select new CustomCallLog
{
Score =
CallLog = i.CallID,
Name = p.Assignee1,
Yr = year,
Mth = i.ClosedDate.Substring(5, 2),
GroupName = p.GroupName
};
return result;
}
public IQueryable<CustomClosedJobs> GetCustomClosedJobs()
{
var result = from i in this.ObjectContext.CallLogs
where i.CallStatus == "Closed" && i.ClosedDate.Substring(0, 4) =="2012"
group i by i.ClosedDate.Substring(5,2) into y
select new CustomClosedJobs
{
Type = "heat",
ClosedCalls = y.Count(),
Mth =y.Key
};
return result;
}
// TODO:
// Consider constraining the results of your query method. If you need additional input you can
// add parameters to this method or create additional query methods with different names.
// To support paging you will need to add ordering to the 'Subsets' query.
public IQueryable<Subset> GetSubsets()
{
return this.ObjectContext.Subsets;
}
}
public class HEATDomainService : LinqToEntitiesDomainService<FEEDBACKPRDEntities1>
{
// TODO:
// Consider constraining the results of your query method. If you need additional input you can
// add parameters to this method or create additional query methods with different names.
// To support paging you will need to add ordering to the 'qryStoringLogs' query.
public IQueryable<qryStoringLog> GetQryStoringLogs()
{
return this.ObjectContext.qryStoringLogs.OrderBy(e => e.monthno);
}
public IQueryable<tblStoringLog> GetTop100Logs()
{
return this.ObjectContext.tblStoringLogs.OrderByDescending(e => e.responsetime).Take(100);
}
public IQueryable<tblStoringLog> GetLogCount(DateTime s, DateTime e)
{
return this.ObjectContext.tblStoringLogs.Where(x => x.responsetime >= s && x.responsetime <= e);
}
public IQueryable<qryStoringLog> GetLogs(int year, int mth)
{
return this.ObjectContext.qryStoringLogs.Where(e => e.Month.Equals(mth) && e.yr.Equals(year));
}
public IQueryable<qryStoringLog> GetLogsForYear(int year)
{
return this.ObjectContext.qryStoringLogs.Where(e => e.yr.Equals(year)).OrderBy(e => e.monthno);
}
public DateTime GetFirstDate()
{
return (DateTime)this.ObjectContext.tblStoringLogs.OrderBy(e => e.responsetime).First().responsetime;
}
public DateTime GetLastDate()
{
return (DateTime)this.ObjectContext.tblStoringLogs.OrderByDescending(e => e.responsetime).First().responsetime;
}
public IQueryable<tblCallLogged> GetTblCallLoggeds()
{
return this.ObjectContext.tblCallLoggeds;
}
public IQueryable<tblStoringLog> GetTblStoringLogs()
{
return this.ObjectContext.tblStoringLogs;
}
[Query(IsComposable = false)]
public IQueryable<qryStoringLog> GetTblStoringLogsStatus(int statusid)
{
return this.ObjectContext.qryStoringLogs.Where(e => e.statusid == statusid);
}
public IQueryable<stResponsesLife_Result> LifeTimeResponses()
{
return this.ObjectContext.stResponsesLife().AsQueryable();
}
public IEnumerable<CustomLifetime> GetCustomLifeTime()
{
var result = from i in this.ObjectContext.stResponsesLife().ToList()
select new CustomLifetime
{
Dates = i.Dates,
Vals = (int)i.Vals
};
return result;
}
public int GetAllResponses()
{
return this.ObjectContext.qryStoringLogs.Count();
}
}
Caveats:
Cannot have linked servers, so doing it at the source (SQL Server) is out of the question.
Cannot create a SP and use OpenQuery (well i could but i want to learn to do it correctly), as im sure this isnt the correct way of doing it.
You may need a third type to wrap the two different types returned from each service, but this depends upon how you want to use it.
An ItemsControl wont care about what types are in the collection (Listbox, combobox etc), but GridView type controls might be picky.
Using linq, both lists can simply be merged. Something like the following should do the trick:
collection1.Select(o => (object)o).Concat(collection2.Select(o => (object)o));
The Select and Cast is so that an appropriate generic collection is created by the query.
This can be adjusted to incorporate conversion to your wrapper type too. ie Instead of casting to Object, just return a new instance of your wrapper class instead.
You can even use a Union if appropriate.
Putting it all together:
collection1.Select(o => new MyWrapperType(o))
.Union(collection2.Select(o => new MyWrapperType(o)));
EntityFramework 4.3.1.
What is the best way to have calculated properties which should be stored in db, but are not intended to be retrieved from db?
E.g.
[Column("SOME_COLUMN")]
public ulong SomeColumn
{
get { return /*calculate here*/; }
}
I want the value to be persisted when I'm saving to db. But of course - not getting updated when I load from db. I can have an empty setter alongside... But it doesn't seem to work when the column is Key.
Can I have such a Key-column?
Now I'm getting this error:
EntityFramework error: The value of a property that is part of an object's key does not match the corresponding property value stored in the ObjectContext. This can occur if properties that are part of the key return inconsistent or incorrect values or if DetectChanges is not called after changes are made to a property that is part of the key.
Firstly, make the setter private:
[Column("SOME_COLUMN")]
public ulong SomeColumn { get; private set; }
Secondly, add a calculation method in the object (so it can access the private setter):
public void CaculateSomeColumn(){
this.SomeColumn = /* some calculation */;
}
Thirdly, add a SavingChanges callback to the Repository context object (MyEntities). This callback can be defined in the context constructor, and it should set the calculated field for items of your type (MyPoco) that were added or modified:
public MyEntities(){
this.SavingChanges += (sender, eventArgs) => {
ObjectContext context = sender as ObjectContext;
if (context != null)
{
foreach (ObjectStateEntry entry in
context.ObjectStateManager.GetObjectStateEntries(
EntityState.Added | EntityState.Modified))
{
if (!entry.IsRelationship && (entry.Entity.GetType() == typeof(MyPoco)))
{
var myObject = entry.Entity as MyPoco;
myObject.CalculateSomeColumn();
}
}
}
};
}