I am new to Linq and trying to get a handle on how to bind a drop down to a SQL user defined function.
//Populate the Pledge dropdown
var db = new App_Data.MyDBDataContext();
int? partnerID = Convert.ToInt32(Request.QueryString["PartnerID"]);
var pledges =
from p in db.ufn_AvailablePledgesByPartner(partnerID)
select new
{
PledgeAndPartnerName = p.PledgeAndPartnerName,
PledgeID = p.PledgeID
};
DropDownList ddlPledgeID = (DropDownList)DetailsViewContribution.FindControl("DropDownListPledgeID");
ddlPledgeID.DataSource = pledges;
ddlPledgeID.DataTextField = pledges.PledgeAndPartnerName;
ddlPledgeID.DataValueField = pledges.PledgeID;
The current problem is the last 2 lines where I'm trying to reference properties of the anonymous class. "'System.Linq.IQueryable' does not contain a definition for 'PledgeAndPartnerName' and no extension method..." I naively thought the compiler was supposed to figure this out, but obviously I'm assuming C# is now more dynamic than it really is.
Thanks for any input.
Try this:
ddlPledgeID.DataTextField = "PledgeAndPartnerName";
ddlPledgeID.DataValueField = "PledgeID";
Related
Introduction:
I have an AdvancedDataGrid displaying hierarchical data illustrated by the image below:
The branch nodes "Prosjekt" and "Tiltak" display the sum of the leaf nodes below.
Problem: I want the root node "Tavle" to display the total sum of the branch nodes below. When i attempted to do this by adding the same SummaryRow the sum of the root node was not calculcated correctly(Every node's sum was calculated twice).
dg_Teknikktavles = new AutoSizingAdvancedDataGrid();
dg_Teknikktavles.sortExpertMode="true";
dg_Teknikktavles.headerHeight = 50;
dg_Teknikktavles.variableRowHeight = true;
dg_Teknikktavles.addEventListener(ListEvent.ITEM_CLICK,dg_TeknikktavlesItemClicked);
dg_Teknikktavles.editable="false";
dg_Teknikktavles.percentWidth=100;
dg_Teknikktavles.minColumnWidth =0.8;
dg_Teknikktavles.height = 1000;
var sumFieldArray:Array = new Array(context.brukerList.length);
for(var i:int = 0; i < context.brukerList.length; i++)
{
var sumField:SummaryField2 = new SummaryField2();
sumField.dataField = Ressurstavle.ressursKey + i;
sumField.summaryOperation = "SUM";
sumFieldArray[i] = sumField;
}
var summaryRow:SummaryRow = new SummaryRow();
summaryRow.summaryPlacement = "group";
summaryRow.fields = sumFieldArray;
var summaryRow2:SummaryRow = new SummaryRow();
summaryRow2.summaryPlacement = "group";
summaryRow2.fields = sumFieldArray;
var groupField1:GroupingField = new GroupingField();
groupField1.name = "tavle";
//groupField1.summaries = [summaryRow2];
var groupField2:GroupingField = new GroupingField();
groupField2.name = "kategori";
groupField2.summaries = [summaryRow];
var group:Grouping = new Grouping();
group.fields = [groupField1, groupField2];
var groupCol:GroupingCollection2 = new GroupingCollection2();
groupCol.source = ressursTavle;
groupCol.grouping = group;
groupCol.refresh();
Main Question: How do i get my AdvancedDataGrid's (dg_Teknikktavles) root node "Tavle" to correctly display the sum of the two branch nodes below?
Side Question: How do i add a red color to the numbers of the root node's summary row that exceed 5? E.g the column displaying 8 will exceed 5 in the root node's summary row, and should therefore be marked red
Thanks in advance!
This is a general answer, without code examples, but I had to do the same just couple of days ago, so my memory is still fresh :) Here's what I did:
Created a class A to represent an item renderer data, extended it from Proxy (I had field names defined at run time), and let it contain a collection of values as it's data member. Once accessed through flash_proxy::getPropery(fieldName) it would find a corresponding value in the data member containing the values and return it. Special note: implement IUID, just do it, it'll save you couple of days of frustration.
Extended A in B, added a children property containing ArrayCollection of A (don't try to experiment with other collection types, unless you want to find yourself examining tons of framework code, trust me, it's ugly and is impossible to identify as interesting). Let B override flash_proxy::getPropery - depending of your compiler this may, or may not be possible, if not possible - call some function from A.flash_proxy::getPropery() that you can override in B. Let this function query every instance of A, which is a child of B, asking the same thing, as DataGrid itself would, when building item renderers - this way you would get the total.
When creating a data provider. Create an ArrayCollection of B (again, don't try to experiment with other collections--unless you are ready for lots of frustration). Create Hierarchical data that uses this array collection as a source.
Colors - that's what you use item renderers for, just look up any tutorial on using item renderers, that must be pretty basic.
In case someone else has the same problem:
The initial problem that everything was summed twice, was the result of using the same Array of SummaryField2 (sumFieldArray in the code) for both grouping fields(GropingField2 tavle and kategori)
The Solution to the main question: was to create a new array of summaryfields for the root node(in my intial for loop):
//Summary fields for root node
var sumFieldRoot:SummaryField2 = new SummaryField2();
sumFieldRoot.dataField = Ressurstavle.ressursKey + i;
sumFieldRoot.summaryOperation = "SUM";
sumFieldArrayRoot[i] = sumFieldRoot;
Answer to the side question:
This was pretty much as easy as pointed out by wvxyw. Code for this solution below:
private function summary_styleFunction(data:Object, col:AdvancedDataGridColumn):Object
{
var output:Object;
var field:String = col.dataField;
if ( data.children != null )
{
if(data[field] >5){
output = {color:0xFF0000, fontWeight:"bold"}
}
else {
output = {color:0x006633, fontWeight:"bold"}
}
//output = {color:0x081EA6, fontWeight:"bold", fontSize:14}
}
return output;
}
How to make a kind of array that index things based on a object? but not being strict like dictionary.
What I mean:
var a:Object = {a:3};
var b:Object = {a:3};
var dict:Dictionary = new Dictionary();
dict[a] = 'value for a';
// now I want to get the value for the last assignment
var value = dict[b];
// value doesn't exits :s
How to make something like that. TO not be to heavy as a lot of data will be flowing there.
I have an idea to use the toString() method but I would have to make custom classes.. I would like something fast..
Why not make a special class that encapsulates an array, put methods in there to add and remove elements from the array, and then you could make a special method (maybe getValueByObject(), whatever makes sense). Then you could do:
var mySpecialArrayClass:MySpecialArrayClass = MySpecialArrayClass();
var a:Object = {a:3};
var b:Object = {a:3};
mySpecialArrayClass.addElement(a,'value for a');
var value = mySpecialArrayClass.getValueByObject(a);
I could probably cook up a simple example of such a class if you don't follow.
Update:
Would something like this help?
http://snipplr.com/view/6494/action-script-to-string-serialization-and-deserialization/
Update:
Could you use the === functionality? if you say
if ( object === object )
it compares the underlying memory address to see if two objects are the same reference...
so.... eval() out of the question, any idea to do this? I also don't know how to use "this" expression or set() in actionscript 3 ( i seem couldn't find any complete reference on it ), just say through php file a multiple variable (test1, test2, test3,...) sent by "echo", how the flash aplication recieved it? I'm trying not to use xml on mysql to php to flash aplication. Simply how to change a string to a variable ?
example
(in as3-actions frame panel)
function datagridfill(event:MouseEvent):void{
var varfill:URLVariables = new URLVariables();
varfill.tell = "do it";
var filler:URLRequest = new URLRequest();
filler.url = "http://127.0.0.1/flashdbas3/sendin.php";
filler.data = varfill;
var filling:URLLoader = new URLLoader();
filling.dataFormat = URLLoaderDataFormat.VARIABLES;
filling.load(filler);
filling.addEventListener(Event.COMPLETE, datain);
function datain(evt:Event){
var arraygrid:Array = new Array();
testing.text = evt.target.Name2 // worked
// just say i = 1
i=1;
arraygrid.push({Name:this["evt.target.Name"+i],
Test:this.["evt.target.Test"+i]}); // error
//or
arraygrid.push({Name:this["Name"+i],
Test:this.["Test"+i]}); // error too
// eval() noexistent, set() didn't worked on actions frame panel
//?????
}
};
I hope it's very clear.
You could use this[varName] if I understand your question right.
So if varName is a variable containing a string which should be a variables name, you could set and read that variable like this:
this[varName] = "someValue";
trace(this[varName]);
Update:
In your example, you could try: evt.target["Test"+i] instead of Test:this.["evt.target.Test"+i]
If you have a set of strings that you'd like to associate with values, the standard AS3 approach is to use an object as a hash table:
var o = {}
o["test1"] = 7
o["test2"] = "fish"
print(o["test1"])
Given this code:
dgIPs.DataSource =
from act in Master.dc.Activities
where act.Session.UID == Master.u.ID
select new
{
Address = act.Session.IP.Address,
Domain = act.Session.IP.Domain,
FirstAccess = act.Session.IP.FirstAccess,
LastAccess = act.Session.IP.LastAccess,
IsSpider = act.Session.IP.isSpider,
NumberProblems = act.Session.IP.NumProblems,
NumberSessions = act.Session.IP.Sessions.Count()
};
How do I pull the Distinct() based on distinct Address only? That is, if I simply add Distinct(), it evaluates the whole row as being distinct and thusly fails to find any duplicates. I want to return exactly one row for each act.Session.IP object.
I've already found this answer, but it seems to be a different situation. Also, Distinct() works fine if I just select act.Session.IP, but it has a column I wish to avoid retrieving and I'd rather not have to do this by manually binding my datagrid columns.
dgIPs.DataSource =
from act in Master.dc.Activities
where act.Session.UID == Master.u.ID
group act by act.Session.IP.Address into g
let ip = g.First().Session.IP
select new
{
Address = ip.Address,
Domain = ip.Domain,
FirstAccess = ip.FirstAccess,
LastAccess = ip.LastAccess,
IsSpider = ip.isSpider,
NumberProblems = ip.NumProblems,
NumberSessions = ip.Sessions.Count()
};
Or:
dgIPs.DataSource =
from act in Master.dc.Activities
where act.Session.UID == Master.u.ID
group act.Session.IP by act.Session.IP.Address into g
let ip = g.First()
select new
{
Address = ip.Address,
Domain = ip.Domain,
FirstAccess = ip.FirstAccess,
LastAccess = ip.LastAccess,
IsSpider = ip.isSpider,
NumberProblems = ip.NumProblems,
NumberSessions = ip.Sessions.Count()
};
One of the overloads of Enumerable.Distinct accepts an IEqualityComparer instance. Simply write a class that implements IEqualityComparer and which only compares the two Address properties.
Unfortunately, you'll have to give a name to the anonymous class you're using.
My appologies upfront for the lengthy question. I made quite an effort to make my question as clear as possible in one go. Please bear with me. ;o) any help will be greatly appreciated!
I have the classes Branch and Text:
class Branch
int ID
Text WebDescription
and a bunch of other properties
class Text
int ID
string UK
string NL
string FR
string IT
and a bunch of other properties as well
I want to only display the ID of the branch and its description in the appropriate language. I want only one query (no extra round trips) which retrieves only two fields (not the whole object).
I found three solutions
Via the object model in the query
// good: no round trips
// good: clean sql
// bad: impossible to use the currentUserLanguage parameter
var lang = "NL";
var dbProject = new ProjectDataContext();
var query = from b in dbProject.GetTable<Branch>()
select new
{
b.ID,
WebDescription = b.WebDescriptionObject.NL // <-- problem
};
var text = query.First().WebDescription;
Via the object model after the query
// good: no round trips (eager loading of text object)
// good: possible to use the currentUserLanguage parameter
// bad: loads the *whole* branch and text object, not just two fields
var lang= "NL";
var dbProject = new ProjectDataContext();
var query = from b in dbProject.GetTable<Branch>()
select new
{
b.ID,
WebDescription = b.GetWebDescriptionAsString(lang)
};
var text = query.First().WebDescription;
Using an expression
// good: I have the feeling I am on the right track
// bad: This doesn't work :o( throws an exception
var lang= "NL";
var dbProject = new ProjectDataContext();
var query = from b in dbProject.GetTable<Branch>()
select new
{
b.ID,
WebDescription = b.GetWebDescriptionAsExpression(lang)
};
var text = query.First().WebDescription;
Here is code for the two methods GetWebDescriptionAsString and GetWebDescriptionAsExpression.
public string GetWebDescriptionAsString(string lang)
{
if (lang== "NL") return WebDescriptionObject.NL;
if (lang== "FR") return WebDescriptionObject.FR;
if (lang== "IT") return WebDescriptionObject.IT;
return WebDescriptionObject.UK;
}
public Expression<Func<Branch, string>> GetWebDescriptionAsExpression(string lang)
{
if (lang== "NL") return b => b.WebDescriptionObject.NL;
if (lang== "FR") return b => b.WebDescriptionObject.FR;
if (lang== "IT") return b => b.WebDescriptionObject.IT;
return b => b.WebDescriptionObject.UK;
}
Without really answering the question, the cleanest approach would be to change the Text structure into a more normalized form like:
Text
ID
TextTranslation
ID
TextID
Lang
TextValue
where each text has a number of translations, one for each language.
The query would become something like:
var q =
from branch in dbProject.Branches
join text in dbProject.Texts on branch.TextID = text.ID
join translation in dbProject.TextTranslations on text.ID = translation.TextID
where translation.Lang == lang
select new
{
branch.ID,
WebDescription = translation.TextValue
};
This approach has other advantages as well, for example adding a new language will not change the model structure.
This would be very easy to do if you used a stored procedure. Are you opposed to using SP's as a solution?
If a stored procedure works, then I am happy to use it.
Thank you for you prompt reply.
I made a quick attempt. The UDF was already there, I just didn't know how to use it. The performance dropped significantly. The first solution is 3 times faster. In my understanding, this approach would require extra round trips to the database. Is that correct?
var query = from b in dbProject.GetTable<Branch>()
select new
{
b.ID,
WebDescription = db.fGetText(b.WebDescriptionID, (currentUserLanguage))
};
Without understanding your whole problem
create a stored procedure like this:
CREATE PROCEDURE spGetTheTextINeed #Language char(2), #BranchID int
AS
/* I don't know how your database is structured so you need to write this */
SELECT MyText from MyTable WHERE Language=#Language and Branch=#BranchID
Then you need to add the sp to your DBML and then you can just call the sp you need with the appropriate parameters:
var query = myDataContext.spGetTheTextINeed("NL",[your branch number])
Dim str As String
str = query.MyText
The code above is not to be exact - I don't understand your full requirements but this should get you started.