LinQ to SQL adding delimited data but checking for duplicates - linq-to-sql

I have a table of Contacts, and a table of Groups which has a many-to-many relationship managed by a simple contacts_groups table:
contacts_groupsID Identity INT
ContactID INT
GroupID INT
I have a delimted String of contact IDs e.g. "1|23|987|2346|33|9821|" which I need to insert into the contacts_groups table (along with the groupID). I am using LinQ to SQL and C#, but want to know the most efficient way of looping through the delimited string (probably .Split()) checking for duplicates and inserting if not exist.

List<int> requested = contactIds.Split('|')
.Select(s => int.Parse(s))
.Distinct()
.ToList();
List<int> existing = (
from x in db.GroupsContacts
where x.GroupId == groupId
select x.ContactId
).ToList();
List<int> toBeAdded = requested.Except(existing).ToList();
foreach(int id in toBeAdded)
{
GroupsContacts record = new GroupsContacts();
record.GroupID = groupID;
record.ContactID = id;
db.InsertOnSubmit(record);
}
db.SubmitChanges();

Related

Convert complex nested selects in Entity Framework query

I need to create a table in View by this View Model:
public class ApplicationContentViewModel
{
public BPMSPARS.Models.MySql.application application {get; set;}
public BPMSPARS.Models.MySql.content content { get; set; }
public BPMSPARS.Models.MySql.app_delegation app_delegation { get; set; }
}
But the query for creating new Table is very complex.
I use this query in MySQL, and I can get correct results by using it.
SELECT APP_UID, (SELECT CON_VALUE FROM content WHERE CON_CATEGORY = 'PRO_TITLE' AND CON_ID =
(SELECT PRO_UID from app_delegation WHERE del_thread_status='open' and USR_UID = '00000000000000000000000000000001' AND APP_UID = '9134216305aaaea1b67c4e2096663219')) AS TASK_NAME,
(SELECT CON_VALUE FROM content WHERE CON_CATEGORY = 'TAS_TITLE' AND CON_ID =
(SELECT TAS_UID from app_delegation WHERE del_thread_status='open' and USR_UID = '00000000000000000000000000000001' AND APP_UID = '9134216305aaaea1b67c4e2096663219')) AS PROCESS_NAME FROM app_delegation
WHERE del_thread_status='open' and USR_UID = '00000000000000000000000000000001' AND APP_UID = '9134216305aaaea1b67c4e2096663219'
But, I have to convert this query in linq or EF in MVC.
How Can I write This Query in Entity Framework query?
And How Can I display results in View?
Your SQL query seems (very) peculiar to me, as it is quite redundant. I am going to assume the sub-queries return a single value and enforce it with LINQ.
First I pulled out the common sub-query over app_delegation:
var USR_APP_Delegation = from a in app_delegation
where a.del_thread_status == "open" &&
a.USR_UID == "00000000000000000000000000000001" &&
a.APP_UID == "9134216305aaaea1b67c4e2096663219"
select a;
In LINQ it is easy to combine the two UID queries into one query:
var UIDs = (from a in USR_APP_Delegation
select new { a.PRO_UID, a.TAS_UID })
.Single();
Now you can do the name subqueries:
var TASK_NAME = (from c in content
where c.CON_CATEGORY == "PRO_TITLE" &&
c.CON_ID == UIDs.PRO_UID
select c.CON_VALUE)
.Single();
var PROCESS_NAME = (from c in content
where c.CON_CATEGORY == "TAS_TITLE" &&
c.CON_ID == UIDs.TAS_UID
select c.CON_VALUE)
.Single();
Then you can put all the queries together for the final result:
var ans = (from a in USR_APP_Delegation
select new {
a.APP_UID,
TASK_NAME,
PROCESS_NAME
})
.Single();
Again, this makes it obvious that your e.g. returning APP_UID when you know exactly what it is, and you are combining TASK_NAME and PROCESS_NAME into a query for no real advantage.
I would suggest using join against content makes a much more understandable query (even in SQL) and makes it clearer what is being returned:
var names = from a in app_delegation
join cpro in content on new { CON_ID = a.PRO_UID, CON_CATEGORY = "PRO_TITLE" } equals new { cpro.CON_ID, cpro.CON_CATEGORY }
join ctas in content on new { CON_ID = a.PRO_UID, CON_CATEGORY = "TAS_TITLE" } equals new { ctas.CON_ID, ctas.CON_CATEGORY }
where a.del_thread_status == "open" &&
a.USR_UID == "00000000000000000000000000000001" &&
a.APP_UID == "9134216305aaaea1b67c4e2096663219"
select new {
a.APP_UID,
Task_Name = ctas.CON_VALUE,
Process_Name = cpro.CON_VALUE
};

Cannot Seem to retrieve data from table in the order of the database table's column order

I want to to retrieve data from table in the order of the database table's column order.
Suppose my sql query is
String sql_string = "select * "
+ "from CUSTOMER_INFO "
+ "order by customer_last_name, customer_first_name";
Session session = factory.openSession();
Transaction tx = session.beginTransaction();
List<Map<String,Object>> results = session.createSQLQuery(sql_string)
.setResultTransformer(AliasToEntityMapResultTransformer.INSTANCE)
.list();
In database, the table's column order is like A,B,C,D.
But when I retrieve the data and iterate through it, the entrySet is like C,A,D,B. (int,float,float,String)
I think the data is being retrieved based on its datatype.
I need the retrieved entrySet in the same order as it exists in database's table.
I also tried specifying the column names in select query which was of no use.
CUSTOMER_INFO is model class mapped to sqllite through hibernate.
#Entity
#Table(name = "CUSTOMER_INFO")
public class CustomerInfo{
#Column
private int C;
#Column
private float A;
#Column
private String B;
#Column
private float D;
//getters and setters
}
Using Sqllite 3.6, hibernate, JSP.
Any help is appreciated.

Why is LINQ to SQL Omitting Columns in Select

I'm using LINQ to SQL to select records. I need to union two queries together but the select statements are being changed so that the expressions no longer match preventing the union.
This LINQ query omits my forced columns 'resultType' and 'imageFile' from the final result.
var taglist = from t in dc.ProductTags
where t.Tag.StartsWith(prefixText)
select new AutoSearch {
resultType = "Tag",
name = t.Tag,
imageFile = string.Empty,
urlElement = t.Tag };
This is the query that is presented.
{SELECT [t0].[Tag] AS [name] FROM [dbo].[ProductTag] AS [t0] WHERE [t0].[Tag] LIKE #p0}
This is the second query to be unioned with the initial one.
var brandlist = from b in dc.Businesses
join t in dc.Tags on b.BusinessId equals t.BusinessId
where b.Name.StartsWith(prefixText)
where b.IsActive == true
where t.IsActive == true
select new AutoSearch
{
resultType = "Business",
name = b.Name,
imageFile = t.AdImage,
urlElement = b.BusinessId.ToString() };
This is the sql for the second query.
SELECT [t0].[Name] AS [name], [t1].[AdImage] AS [imageFile], CONVERT(NVarChar(MAX) [t0].[BusinessId]) AS [urlElement] FROM [dbo].[Business] AS [t0] INNER JOIN [dbo].[Tag] AS [t1] ON ([t0].[BusinessId]) = [t1].[BusinessId] WHERE ([t0].[Name] LIKE #p0)
The union... that throws the error.
var unionedResults = taglist.Union(brandlist);
The error thrown.
All queries combined using a UNION, INTERSECT or EXCEPT operator must have an equal number of expressions in their target lists.
This is the AutoSearch class.
public class AutoSearch
{
public string name { get; set; }
public string imageFile { get; set; }
public string resultType { get; set; }
public string urlElement { get; set; }
}
Suggestions as to what is going???
UPDATE***
Found a work around...
Found the issue.
This is a known bug in LINQ, several discussions found here on SO that pointed me in the right direction. Turns out most of the work arounds listed on the site are no longer valid because version 4.0 of broke them too. I found another that worked..
LINQ omits duplicate values for optimization purposes. I was able to change the values of the throw away fields by converting them to strings or lower case or concatenating them.
Terribly inefficient, but it works. Whole day lost for me on this one, perhaps it will save others time.
var taglist = from t in dc.ProductTags
where t.Tag.StartsWith(prefixText)
let resultType = "Tag"
select new AutoSearch() {
resultType = resultType,
name = t.Tag,
imageFile = t.Tag.ToString(),
urlElement = t.Tag.ToLower()
};
var brandlist = from b in dc.Businesses
join t in dc.Tags on b.BusinessId equals t.BusinessId
where b.Name.StartsWith(prefixText)
where b.IsActive == true
where t.IsActive == true
where t.AdImage != null
where t.AdImage != String.Empty
let resultType = "Business"
select new AutoSearch
{
resultType = resultType,
name = b.Name,
imageFile = t.AdImage,
urlElement = b.BusinessId.ToString()
};
The only property you reference when you do the select part of your query is Tag, Linq to Sql knows this and optimizes the query to only select columns you're referencing.
In other words, this section of your query only refers to the "Tag" property, which is tied to the Tag column on your database.
new AutoSearch {
resultType = "Tag",
name = t.Tag,
imageFile = string.Empty,
urlElement = t.Tag };
What Linq does in this case is pass an expression to the underlying provider (very similar to a binary tree data structure). The provider then parses this tree and creates a SQL query from it at run time. The optimization is done by the provider at runtime which results in the SQL query you're seeing.
Update
For the second problem with the union you basically are trying to union two different SQL statements which is causing the union error. So lets take a look.
The resulting statement that would be causing the error would look something like this
SELECT [t0].[Tag] AS [name] FROM [dbo].[ProductTag] AS [t0] WHERE [t0].[Tag] LIKE #p0
UNION
SELECT [t0].[Name] AS [name], [t1].[AdImage] AS [imageFile], CONVERT(NVarChar(MAX) [t0].[BusinessId]) AS [urlElement] FROM [dbo].[Business] AS [t0] INNER JOIN [dbo].[Tag] AS [t1] ON ([t0].[BusinessId]) = [t1].[BusinessId] WHERE ([t0].[Name] LIKE #p0)
Obviously this is problametic since there is not the same number of columns between the two and that doesn't fly with SQL. While I do not have a pure linq solution there is a workaround.
First You'll need to create a SQL function that just returns a string sent to it.
CREATE FUNCTION ReturnString( #string varchar(max) )
RETURNS varchar(max)
AS
BEGIN
RETURN #string
END
GO
Next drag and drop this new SQL function into your dbml file, and finally in your query simply call the method where appropriate.
var taglist = from t in dc.ProductTags
where t.Tag.StartsWith(prefixText)
select new AutoSearch
{
resultType = dc.ReturnString("Tag"),
name = t.Tag,
imageFile = dc.ReturnString(string.Empty),
urlElement = dc.ReturnString(t.Tag)
};
var brandlist = from b in dc.Businesses
join t in dc.Tags on b.BusinessId equals t.BusinessId
where b.Name.StartsWith(prefixText)
where b.IsActive == true
where t.IsActive == true
select new AutoSearch
{
resultType = dc.ReturnString("Business"),
name = b.Name,
imageFile = t.AdImage,
urlElement = b.BusinessId.ToString()
};
Now you should be able to perform the union.

Not returning all the required rows using MySQL

so here is my issue:
i have 3 tables:
ROLE : RID ,NAME
CLIENT : CID, NAME
USER : UID, RID, CID, USERNAME, PASSWORD
Below is the SQL statement that I have written:
SELECT USER.UID,USERNAME,PASSWORD,ROLE.NAME, ROLE.RID
FROM USER
INNER JOIN ROLE ON USER.RID=ROLE.RID
WHERE CID=1;
The above statement is returning only 1 row when there should actually be 2 rows.
I don't understand what is not working.
When i do the following, i get my 2 rows:
SELECT *
FROM USER
WHERE CID =1;
Note that i am using spring framework and also implementing a RowMapper. Below is my actual code with the field names as per the dbase.
public List<User> viewUserClient(int client_id) {
String sql =
"SELECT USER.ID,USERNAME,PASSWORD,ACTIVE,ROLE.NAME, ROLE.ID FROM USER INNER JOIN ROLE ON USER.ROLE_ID=ROLE.ID WHERE CLIENT_ID=?";
List<User> users = this.getJdbcTemplate().query(sql, new Object[] { client_id }, new UserClientRowMapper());
return users;
}
private static final class UserClientRowMapper implements RowMapper<User> {
public User mapRow(ResultSet rs, int rowNum) throws SQLException {
User user = new User();
Client client = new Client();
Role role = new Role();
user.setID(rs.getInt("ID"));
user.setUSERNAME(rs.getString("USERNAME"));
user.setPASSWORD(rs.getString("PASSWORD"));
user.setACTIVE(rs.getBoolean("ACTIVE"));
role.setNAME(rs.getString("NAME"));
role.setID(rs.getInt("ROLE.ID"));
client.setId(rs.getInt("id"));
client.setName(rs.getString("name"));
user.setRole(role);
user.setClient(client);
return user;
}
}
Thanks in advance for your help.
The INNER JOIN keyword returns rows when there is at least one match in both tables. If there are rows in "USER" that do not have matches in "ROLE", those rows will NOT be listed; of the two users returned by your plain select query, probably one has a null RID column value, or a value that is not in ROLE table.
Use a LEFT JOIN.

How to read row by row data from table like SQLReader using LINQ

May anybody tell me how to replace this code using Linq ?
using using Microsoft.Practices.EnterpriseLibrary.Data;
Public IDataReader GetRowByRowData()
{
Database Db = DatabaseFactory.CreateDatabase();
string sqlString = "SELECT * FROM TableTest";
DbCommand DbCmd = PpwDb.GetSqlStringCommand(sqlString);
Db .ExecuteReader(DbCmd);
}
Please help to get row by row data from table TableTest using Linq
you can do that like this:
var myQyery=from a in dataContext.Mytable
select a;
foreach(var item in myQuery)
{
//what you like
}
var records = (from p in context.TableTest
select p).ToList();
foreach(var record in records) {
// loop through each record here
}
ToList method will query the database and get the result set.
I load the primary key from my table into a list. Depending on the size of the data set and the primary key, loading into a list does not take too long. After loading the keys, use FirstOrDefault() with a where clause like so:
var keys = Db.TableTest.Select(x => x.primaryKey).ToList();
foreach (var k in keys)
{
var record = (from i in Db.TableTest
where i.primaryKey == k
select new
{
//Select only the columns you need to conserve memory
col1 = i.col1,
col2 = i.col2
}).FirstOrDefault();
//Process the record
}