Pass a table method to addLink method of a QueryBuildDataSorce object - axapta

Is there any way to pass a table method instead of fieldid to addLink method of a QueryBuildDataSource object?
I have this code:
qbdsLedgerTrans.addLink(
FieldNum(LedgerTable, AccountNum), // Here i need to pass a conditional value of a LedgerTable method instead of a field
FieldNum(LedgerTrans, AccountNum)
);

I think no because the query API is tightly bound to tables in SQLServer and tables does not contain any method in SQLServer.
The #addLink will be used to generate query join statement so there must use data present inside the database and method are not in the database but in the aod files.
Depending on what you want to do you can have a method to encapsulate your logic and return the corrected fieldId.

The first argument to the addLink method must be an field of the prior joined table, in this case LedgerTable. It may be returned by a function, but I doubt it will solve your hidden (unstated) problem.
The second argument to the addLink method must be an field of the current datasource table.
In other scenarios (form delayed joins) you could use the addDynalink method instead.

Related

Object Mapping from stored procedure using the columnname attribute in EntityFramework CodeFirst

I have an existing db that I am using entityframework 6 Code-First on to work with. A requirement though is that all work with the db has to be via stored procedures. So I started out using the mapping that is new in 6.0:
modelBuilder.Entity<Post>().MapToStoredProcedures();
The issue is that this only supports mapping Insert, Update, and Delete sp's not the select sp's, I need to be able to us a sp to select. (I do not have access to edit any of the existing sp's)
My poco's have attributes on them specifying the column name's to use using the column attribute. Apparently though the built in mapping does not support using those unless you are doing a direct selection on the table via a dbset object.
Originally I had (which worked):
return (from c in DataContext.Current.AgeRanges orderby c.StartAge select c);
Then to switch it to the sp I tried (using the database sqlquery call):
return DataContext.Current.Database.SqlQuery<AgeRange>("[DIV].[GetAgeRangesList]").AsQueryable();
This returned valid objects, but none of the columns marked with the Column attribute had anything in them.
Then I tried (thinking since it was against the actual dbset object I'd get the column mapping):
return DataContext.Current.AgeRanges.SqlQuery("[DIV].[GetAgeRangesList]").ToList().AsQueryable();
Nope, this instead gave me an error that one of the properties in the POCO object (one of the Column attribute ones) was not found in the returned recordset.
So the question is, in entity framework (or best solution outside of that) what is the best way to call a stored procedure and map the results to objects and have that mapping respect the column attribute on the properties?
I would even be willing to use an old school Table object and a SqlCommand object to fill it, if I had a fast easy way to then map the objects that respects the Column Attribute.
SqlQuery does not honor Column attribute. If the names of the columns of the returned result set match the names of the properties of the entity the properties should be set accordingly. Note however that SqlQuery does only minimal amount of work (for instance it does not support relationships (.Include)) so you are limiting yourself if you decide using stored procedures for queries.
Enhancing SqlQuery to use ColumnName attributes is being tracked here: https://entityframework.codeplex.com/workitem/233 - feel free to upvote this codeplex item.

Entity Framework 5, Code First, Full Text Search but IQueryable via CreateQuery?

I am using .NET 4.5 and EF 5 with Code First approach and now I need to implement Full Text Search.
I have already read a lot about it and so far my conclusions are:
Stored procedures nor Table Value Functions can not be mapped with Code First.
Still I can call them using dynamic sql
dbContext.Database.SqlQuery<Movie>(Sql, parameters)
But this returns IEnumerable and I want IQueryable so that I can do more filtering before fetching the data from db server. I know I can send those parameters to Db function but I don't want that.
What I have found that could fulfill my needs is CreateQuery function from IObjectContextAdapter that looks like this(Select All just for test):
IQueryable<Movie> result = ((IObjectContextAdapter)dbContext).ObjectContext.CreateQuery<Movie>("SELECT * FROM Movie");
However executing this throws Exception"
'System.Data.EntitySqlException was unhandled
HResult=-2146232006
Message=The query syntax is not valid. Near term '*', line 1, column 9.'
So the questions are:
Why do I get this exception and can it be fixed ?
If not is there any way with Code First to do FTS that returns IQueryable ?
Try it like this
ObjectQuery<Movie> query =
objectContext.CreateQuery<Movie>(#"SELECT VALUE movie FROM Movies");
As for why see these links
Differences from Transact-SQL Unlike Transact-SQL, Entity SQL does not
support use of the * argument in the SELECT clause. Instead
Entity SQL Reference - SELECT
"SELECT VALUE" - value keyword in LINQ/Entity Framework query

how to add records from DataTable to ArrayList using AddRange Method

Hey guys,
i have a dataTable, which contains a column which has 100 rows, now i want to add those rows in ArrayList, but not with the Add Method, because i have to use for loop for adding records one by one, so i want to prefer addrange method of arraylist, so it is possible to add records in arraylist from DataTable using AddRange.
Below is the code which i am using.
Dim adapGetImages As New SqlDataAdapter("select distinct FileName from Files where Filename<>'' and (RIGHT(FileName,3) = 'gif' or RIGHT(FileName,3) = 'jpg' or RIGHT(FileName,3) = 'bmp') order by FileName", connection)
Dim dtGetImages As New DataTable()
adapGetImages.Fill(dtGetImages)
ArrayList1.AddRange(dtGetImages.Rows[0][0].ToString())
The last line is where i am stuck. as if i run this it will just add single row, and if i say dtGetImages.Rows.ToString() then this will just Add System.DataRow in Arraylist and not its content.
Please reply what could be done for resolving this issue without any loops.
Thanks in Advance.
Something like this should work:
ArrayList1.AddRange(dtGetImages.Rows.Cast(Of DataRow)().[Select](Function(r) r(0).ToString()).ToArray())
Update
There are a few concepts at work here. First of all, you're not trying to add the rows to the list, but rather the first value in each row. As you mentioned, you could use a for loop to get this value out of each row and add it to a list, but loops like that aren't very concise or declarative. This is why we have LINQ (Language-Integrated Queries): a framework that simplifies the transformation of collections of values.
The Select method is an extension method defined in the LINQ framework. It takes as an argument a function that defines what transformation to perform on each item in the given collection. When the result of the Select is invoked, the given function is performed on each value, producing a new collection based on the results. Here we give it the function:
Function(r) r(0).ToString()
..., which tells it:
Given a variable r, get the zeroth index of r and call ToString() on the result.
So if this Select method is called on an IEnumerable<DataRow>, the resulting collection will be an IEnumerable<string>. Since the ArrayList.AddRange method requires an ICollection, we have to change our IEnumerable<string> into something that implements ICollection. As it turns out, arrays implement ICollection, so we can use the ToArray() method from LINQ to convert it into a value that ArrayList.AddRange will accept.
There's just one problem: the DataTable class was written before generics were part of the .NET framework, so the DataRowCollection class implements the non-generic IEnumerable interface rather than the strongly-typed IEnumerable<DataRow>. Since our Select method needs to start with an IEnumerable<DataRow>, we have to do something to convert dtGetImages.Rows into a IEnumerable<DataRow>. The Cast method, also provided by LINQ, will do this for us. We tell Cast that we happen to know that everything in the given IEnumerable (the DataRowCollection in this case) is going to be a DataRow, so it can safely cast each item into a DataRow, leaving us with the IEnumerable<DataRow> that we need to use the Select method on.
Hopefully that explains things pretty well. One thing you should be aware of is that this doesn't eliminate the use of loops. When you call .ToArray(), it pulls items from the .Select, which pulls items from the .Cast, which iterates over dtGetImages.Rows the same as if you'd written a for loop to populate an array. The only difference is that LINQ makes your code more declarative. It's the difference between saying:
For each DataRow in the Rows property of this DataTable, I'm going to create a variable called row. Then I will call ToString on the zeroth element of this variable and add the result to the ArrayList.
... and saying:
I am calling ToString on the zeroth element out of each DataRow in the Rows property of this DataTable, and adding the results to the ArrayList.
They both mean roughly the same thing, but one is both clearer and more concise.
The MSDN page for the Fill method has this note:
When handling batch SQL statements that return multiple results, the implementation of Fill and FillSchema for a .NET Framework data provider retrieves schema information for only the first result.
Are you getting the schema information for the first result?

linq to sql "Contains"

if i have a field in my table that i want to verify exists, how do i use the contains method to determine if it exists.
i would have thought the contains method just takes in a string but it seems to take in my whole linq data object
Contains is an extension method for IEnumerable that determines whether a given object is present in the enumerable. That's not what you want here.
I'm guessing that you have a LINQ query like this:
IEnumerable<string> productNames = from p in db.Products select p.ProductName;
And now you want to verify that the ProductName field actually exists to avoid run-time errors. There is actually no need to check that. Try replacing p.ProductName by a field that doesn't exist. The compiler will complain.
Of course, this assumes that the actual database schema matches the one used to generate the database class with MSLinqToSQLGenerator.
Not sure how to do it with LINQ but you could do:
SELECT * FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE _NAME ='MyTable' and COLUMN _NAME='MyColumn'
then based on the count returned from the query you will know if the column exists or not.

Cannot insert null where field is Guid (object in SqlDataSource)

I have a table which links to another table in the ASP.NET membership schema.
Problem is, all the PKs for the ASP.NET tables are uniqueidentifier so mine has to be too. When I add a SqlDatasource and call its Insert() method, I get the following error:
Cannot insert the value NULL into column 'DiscountCode', table 'CreamDb.dbo.CustomInfo1'; column does not allow nulls. INSERT fails.
The statement has been terminated.
The uniqueidentifier is also treated as an object (its data type), but there is no Guid data type. I had this problem before, but the schema was much simpler so I could fix it.
How can I go about fixing this? If I get rid of the data type part in the markup (so just leave the field/parameter name but not the data type stuff), I get another error so that is not possible.
Thanks
What do you mean by "there is no Guid data type"? What's wrong with System.Guid? Can't you just use Guid.NewGuid(), set the field appropriately, and do the insert?
EDIT: Just to give a bit more meat: attach an event handler to the Inserting event, and populate the field then, via the DbCommand returned by SqlDataSourceCommandEventArgs.Command. Or change the SQL used by the INSERT command to ask the database to populate the GUID field for you.
A popullar approach when dealing with references to the ASP.NET Membership Provider's data is, instead of keeping a proper foreign key to the GUIDs, instead store something like the LoweredUserName in your table. Then, use the Membership Provider's API to interact with the object you need. In some cases, you need an ObjectDataSource abstraction layer to accomplish CRUD scenarios.
Set the default value of the column in SQL Sever to "newid()".
Asp.net won't send the value, and the field will get a new guid.

Resources