I'm trying to bind an ASP.net DropDownList to the results of an entity framework query, while still maintaining multi-tier separation. (i.e. I don't want my UI code to contain query details, nor my Data Layer code to have UI dependencies.) My code-behind in the Page_Load event handler looks like this:
IEnumerable<Lookup> TypesLookup = Business.DocumentBO.GetDocumentTypes(_LookupTypeID);
DocTypeDropDownList.DataSource = TypesLookup;
DocTypeDropDownList.DataTextField = "Description";
DocTypeDropDownList.DataValueField = "LookupID";
DocTypeDropDownList.DataBind();
While my data code looks like this (there's an intermediate business layer as well, but there no processing there as yet -- just a pass-through.):
public static IEnumerable<Lookup> GetLookups(int LookupTypeID)
{
using (VLFDocumentEntities context = new VLFDocumentEntities())
{
IEnumerable<Lookup> l = (from c in context.Lookup
where c.LookupTypeID == LookupTypeID
select c);
return l;
}
}
When I get to the DocTypeDropDownList.DataBind();, it throws an ObjectDisposedException with the message "DocTypeDropDownList.DataBind();". Can anyone advise me on the best way to tackle this?
Thanks,
Andy
Don't you have to detach the objects from the context? E.g:
IEnumerable<Lookup> l = (from c in context.Lookup
where c.LookupTypeID == LookupTypeID
select c);
foreach (Lookup lookup in l)
context.Detach(lookup);
return l;
Why don't you just use a List<>?
public static List<Lookup> GetLookups(int LookupTypeID)
{
using (VLFDocumentEntities context = new VLFDocumentEntities())
{
return (from c in context.Lookup
where c.LookupTypeID == LookupTypeID
select c).ToList();
}
}
Related
I'm obtaining data from an external service and inserting it into an inMemory table (Table_movieTemp), which I use as a datasource on a form (Form_MovieSearch_ds):
[FormControlEventHandler(formControlStr(Form_MovieSearch, FormCommandButtonControl1), FormControlEventType::Clicked)]
public static void FormCommandButtonControl1_OnClicked(FormControl sender, FormControlEventArgs e)
{
FormDataSource Form_MovieSearch_ds = formRun.dataSource();
System.Collections.IEnumerable data = ClassLibrary1.Program::CallRestService();
var enumerator = data.getEnumerator();
while(enumerator.moveNext())
{
MovieRentalService.TmdbMovie item = enumerator.get_current();
Table_movieTemp.Description = item.Description;
Table_movieTemp.ReleaseDate = today();
Table_movieTemp.Title = item.Title;
Table_movieTemp.Rating = item.Rating;
Table_movieTemp.existsAlready = Table_Movie::exist(item.Title);
insertList.add(movieTemp);
}
ttsbegin;
insertList.insertDatabase();
ttscommit;
while select Table_movieTemp
{
info(strFmt("Name: %1,", Table_movieTemp.Title));
}
The while loop I used purely to prove the inserts were succesful.
Afterwards I figure I can call the executeQuery on the form which has my temptable as datasource:
FM_MovieSearch_ds.executeQuery();
This did not work and when I searched google I found a solution where I have to pass the TempTable buffer so that I can link it using 'setTmpTable'.
So I added the following call before calling executeQuery():
formRun.BindTable(movieTemp);
Function on my form:
public void BindTable(FM_MovieTemp _movieTempBuffer)
{
_movieTempBuffer.setTmpData(_movieTempBuffer);
}
Now my code compiles and does not generate runtime errors either, but I still don't see any data. Could someone advice what I miss or do wrong?
The use of in-memory tables in forms has been around for 25 years, and you will find several uses in the standard application.
From the CustVendAgingStatistics form:
void calcAgingStatistics(boolean _research)
{
CustVendAgingStatistics custVendAgingStatistics = CustVendAgingStatistics::construct(linkedCustVendTable, graphData.loadDefName(), graphData.perInvoiceDate());
custVendAgingStatistics.calcStatistic();
tmpAccountSum.setTmpData(custVendAgingStatistics.tmpAccountsum());
if (_research)
{
tmpAccountSum_ds.research();
}
}
Another nice example is found here.
The method:
Insert the records in a separate method, return the local buffer.
In the calling method call setTmpData with the return value.
Research the datasource
In your code I see the use of InsertRecordList, do not use that on in-memory temporary tables, it makes no sense.
Also _movieTempBuffer.setTmpData(_movieTempBuffer) does not do anyting useful as it operates on itself.
Also good style is not do a lot in onClicked methods and other event methods, call proper methods to do the hard work instead.
I need to create a reord in LedgerJournalTrans through x++ code.
While debugging I found out that the class LedgerJournalEngine_CustPayment is used to initiate the form as
LedgerJournalEngine_CustPayment = new LedgerJournalEngine_CustPayment(element)
and later
LedgerJournalEngine.initValue(LedgerJournalTrans);
also after assiging the accountNum the methods executed at the modified() method of datasource field LedgerJournalTrans:AccountNum are element.accountNumModifiedPost(); etc.
While trying to achieve the same through code I am not able to initiate the class LedgerJournalEngine_CustPayment and also the other methods in the form LedgerJournalTransCustPaym that system does.
Pls Help..
Joyce
LedgerJournalEngine* classes are mostly used by the forms to do work and execute code before/after events and datasource actions. What you're trying to do, it would probably just make more sense to complete all of the necessary ledgerJournalTrans fields, then do a .insert(). Here is some code I wrote that will do what you want though using the engine some:
static void Job81(Args _args)
{
LedgerJournalEngine_CustPayment ledgerJournalEngine;
LedgerJournalTable ledgerJournalTable;
LedgerJournalTrans ledgerJournalTrans;
NumberSeq numberSeq;
Voucher voucher;
;
// This just selects the header you are inserting into
select firstonly ledgerJournalTable where ledgerJournalTable.JournalNum == 'GB 0056226';
if (!ledgerJournalTable)
throw error ("Unable to find journal table record");
ledgerJournalTrans.initValue();
numberSeq = NumberSeq::newGetNumFromCode(ledgerJournalTable.VoucherSeries);
if (numberSeq)
{
ledgerJournalTrans.Voucher = numberSeq.num();
voucher = ledgerJournalTrans.Voucher;
}
ledgerJournalTrans.JournalNum = ledgerJournalTable.JournalNum;
ledgerJournalTrans.TransDate = SystemDateGet();
ledgerJournalTrans.AccountType = LedgerjournalACType::Cust;
ledgerJournalTrans.AccountNum = '100003';
ledgerJournalEngine = LedgerJournalEngine::construct(LedgerJournalType::CustPayment);
ledgerJournalEngine.newJournalActive(ledgerJournalTable);
ledgerJournalEngine.accountModified(ledgerJournalTrans);
ledgerJournalTrans.AmountCurCredit = 10;
ledgerJournalTrans.OffsetAccountType = ledgerJournalTable.OffsetAccountType;
ledgerJournalTrans.OffsetAccount = ledgerJournalTable.OffsetAccount;
ledgerJournalTrans.CurrencyCode = CompanyInfo::standardCurrency();
ledgerJournalEngine.currencyModified(ledgerJournalTrans);
ledgerJournalTrans.insert();
if (numberSeq && ledgerJournalTrans.Voucher == voucher)
{
numberSeq.used();
}
else
{
if (numberSeq)
numberSeq.abort();
}
info("Done");
}
i have created dynamic listboxes (4 to 10) in ASP.NET.
and my question is , How do i find the dynamically created listboxes using c#?
thanks
Sure... and i appreciate your help . below code i am using for creating dynamic LB
protected void btndyfilter_Click(object sender, EventArgs e)
{
int numberOfListBox = lbFilter.GetSelectedIndices().Length;
string lbname = lbFilter.SelectedValue;
for (int i = 0; i < numberOfListBox; i++)
{
ListBox listb = new ListBox();
ListItem lItem = new ListItem();
listb.SelectionMode = System.Web.UI.WebControls.ListSelectionMode.Multiple;
listb.Height = 150;
listb.Width = 200;
lItem.Value = i.ToString();
lItem.Text = lbname;
listb.Items.Add(lItem);
panFilter.Controls.Add(listb);
//once we created the LB dynamically i need to populate each LB with the corresponding values
connstr2 = System.Configuration.ConfigurationManager.ConnectionStrings["connstr"].ConnectionString;
conn2.ConnectionString = connstr2;
conn2.Open();
CubeCollection CubeList = conn2.Cubes;
string cb = ddlCubeList.SelectedItem.Text;
//need to remove the Hardcoded Code
foreach (Member dimem in CubeList[cb].Dimensions["Date"].Hierarchies["Calendar Date"].Levels["Date"].GetMembers())
{
ListItem Memlist = new ListItem();
Memlist.Text = dimem.UniqueName;
lbFilter.Items.Add(Memlist);
}
}
panFilter.Visible = true;
panCubeDef.Visible = true;
}
so this will create the LB i believe :)... and Inside the commented code i need to use to populate for each LB item ..perhaps it bit hardcoded which i need to remove. so i all dynamic LBs are populated then the selected items from all LBs will come into the where clause in my MDX query..hope i did not confuse you
There is 2 way either you can store dynamic control detail with dictionary or just find when you want to use it using some code like this
Control GetControlByName(string Name)
{
foreach(Control c in this.Controls)
if(c.Name == Name)
return c;
return null;
}
while generating ListBox dynamically, give ListBox ID as:
lstBoxNo1, lstBoxNo2. lstBoxNo3 etc. where 1,2,3(no) will be from count.
like
int count=1;
generate listbox control
listboxid=lastBoxNo+count;
count++
`by doing this, u have control over id's.
else use
http://stackoverflow.com/questions/3731007/using-findcontrol-to-find-control
using this link to understand findcontrol.
The points that you wont to find that dynamic controls are.
The moment you first render the page.
On every other post back.
In the case of 1, then you better keep a variable on your page that keep that creations.
In the case of 2, when you have post back, you need to store somehow the creations of your control in the page when you render it. One good place is to keep that information on the viewstate.
You can also on the post back, just to check if you have any post back valued from controls that you have named with a serial numbering starting from 1, eg You start looking if you have post back from ControlName_1, then ControlName_2, and when you not found any other value you end.
I'm working on a MVC3 application and I created my POCO classes from my database with the DbContext Code Generator. All goes fine until I got stuck in this situation. Note that I use the repository pattern and I use for every entity a dedicated repository whether get a new instance of the DbContext.
Now, I'm in this situation:
object A has a relation one-to-many with B (A can have one or many B)
object B has a relation many-to-one with C (C can have one or many B)
object B has a relation many-to-one with D (D can have one or many B)
I should add a new object B, consider that object C and D are yet existing, so I must only do the relation and the object A can be created or updated. In the specific consider that A is customer and B is subscriptions (C and D are virtual objects properties in B).
Now If I try to save I got duplicates in C and D tables, while the management of the object seems to work.
So, I thinked that I should detach the entities before do the relation, but when I call the SaveChanges() I got this error:
Store update, insert, or delete statement affected an unexpected number of rows (0). Entities may have been modified or deleted since entities were loaded. Refresh ObjectStateManager entries.
Here's the code:
Customer customer = customerRepository.Get(ID);
if (customer == null)
{
customer = new Customer();
customer.Email = Request.Form["Email"].ToString();
}
Subscription subscription = new Subscription();
subscription.Active = true;
subscription.DateSubscription = DateTime.Today;
Object C = objectCRepository.Get(Request.Form["IDObjectC"]);//Get C object from database
Object D = objectDRepository.Get(Request.Form["IDObjectD"]);//Get D object from database
if (C != null)
{
//I tried also to detach the objects before adding to subscription
subscription.C = C;
subscription.D = D;
customer.Subscriptions.Add(subscription);
if (customer.IDCustomer == 0)
customerRepository.Add(customer);
else
UpdateModel(customer);
customerRepository.Save();
}
And here the add and the save method of the customer repository:
public override void Add(Cliente cliente)
{
db.Cliente.Add(cliente);
}
public override void Save()
{
foreach (var entry in db.ChangeTracker.Entries()
.Where(e => e.State == EntityState.Modified || e.State == EntityState.Added || e.State == EntityState.Unchanged || e.State == EntityState.Detached))
{
string state = ObjectContext.GetObjectType(entry.Entity.GetType()).Name + " " + entry.State.ToString();
if (ObjectContext.GetObjectType(entry.Entity.GetType()).Name.Equals("C") || ObjectContext.GetObjectType(entry.Entity.GetType()).Name.Equals("D"))
{
entry.State = EntityState.Unchanged;
}
dbContext.SaveChanges();
}
I tried also to use this for objects C and D.
((System.Data.Entity.Infrastructure.IObjectContextAdapter)dbContext).ObjectContext.Refresh(System.Data.Objects.RefreshMode.StoreWins, entry);
And the error received is
The element at index 0 in the collection of objects to refresh has a null EntityKey property value or is not attached to this ObjectStateManager.
I noticed that in CTP5 was added the option AsNoTracking(), I tried to use it, but nothing!
I checked also the Concurrency mode for every properties involved in the operation and all are set to None.
I finished ideas :(!
Any help would appreciated! Thanks!
Actually I solved myself using on loading the AsNoTracking() method and before saving the entities I change the state to Unchanged.
//On loading
Context.Object.AsNoTracking().SingleOrDefault(l => l.Property == Property);
//On saving
Object.State = EntityState.Unchanged;
Object.SaveChanges();
Hope this helps someone.
I'm modifying the "Edit.aspx" default page template used by ASP.NET Dynamic Data and adding some additional controls. I know that I can find the type of object being edited by looking at DetailsDataSource.GetTable().EntityType, but how can I see the actual object itself? Also, can I change the properties of the object and tell the data context to submit those changes?
Maybe you have found a solution already, however I'd like to share my expresience on this.
It turned out to be a great pita, but I've managed to obtain the editing row. I had to extract the DetailsDataSource WhereParameters and then create a query in runtime.
The code below works for tables with a single primary key. If you have compound keys, I guess, it will require modifications:
Parameter param = null;
foreach(object item in (DetailsDataSource.WhereParameters[0] as DynamicQueryStringParameter).GetWhereParameters(DetailsDataSource)) {
param = (Parameter)item;
break;
}
IQueryable query = DetailsDataSource.GetTable().GetQuery();
ParameterExpression lambdaArgument = Expression.Parameter(query.ElementType, "");
object paramValue = Convert.ChangeType(param.DefaultValue, param.Type);
Expression compareExpr = Expression.Equal(
Expression.Property(lambdaArgument, param.Name),
Expression.Constant(paramValue)
);
Expression lambda = Expression.Lambda(compareExpr, lambdaArgument);
Expression filteredQuery = Expression.Call(typeof(Queryable), "Where", new Type[] { query.ElementType }, query.Expression, lambda);
var WANTED = query.Provider.CreateQuery(filteredQuery).Cast<object>().FirstOrDefault<object>();
If it's a DD object you may be able to use FieldTemplateUserControl.FindFieldTemplate(controlId). Then if you need to you can cast it as an ITextControl to manipulate data.
Otherwise, try using this extension method to find the child control:
public static T FindControl<T>(this Control startingControl, string id) where T : Control
{
T found = startingControl.FindControl(id) as T;
if (found == null)
{
found = FindChildControl<T>(startingControl, id);
}
return found;
}
I found another solution, the other ones did not work.
In my case, I've copied Edit.aspx in /CustomPages/Devices/
Where Devices is the name of the table for which I want this custom behaviour.
Add this in Edit.aspx -> Page_Init()
DetailsDataSource.Selected += entityDataSource_Selected;
Add this in Edit.aspx :
protected void entityDataSource_Selected(object sender, EntityDataSourceSelectedEventArgs e)
{
Device device = e.Results.Cast<Device>().First();
// you have the object/row being edited !
}
Just change Device to your own table name.