1

Here is the code I'm working with, I'm still a bit new to LINQ, so this is a work in progress. Specifically, I'd like to get my results from this query (about 7 columns of strings, ints, and datetime), and return them to the method that called the method containing this LINQ to SQL query. A simple code example would be super helpful.

using (ormDataContext context = new ormDataContext(connStr))
{
    var electionInfo = from t1 in context.elections
               join t2 in context.election_status
               on t1.statusID equals t2.statusID
               select new { t1, t2 };
}

(In this case, my query is returning all the contents of 2 tables, election and election_status.)

7 Answers 7

5

Specifically, I'd like to get my results from this query (about 7 columns of strings, ints, and datetime), and return them

Hi, the problem you've got with your query is that you're creating an anonymous type. You cannot return an anonymous type from a method, so this is where you're going to have trouble.

What you will need to do is to create a "wrapper" type that can take an election and an election_status and then return those.

Here's a little sample of what I'm talking about; as you can see I declare a Tuple class. The method that you will wrap your query in returns an IEnumerable.

I hope this helps :-)

class Tuple
{
    Election election;
    Election_status election_status;

    public Tuple(Election election, Election_status election_status)
    {
        this.election = election;
        this.election_status = election_status;
    }
}

public IEnumerable<Tuple> getElections()
{
    IEnumerable<Tuple> result = null;

    using (ormDataContext context = new ormDataContext(connStr))
    {
        result = from t1 in context.elections
                 join t2 in context.election_status
                 on t1.statusID equals t2.statusID
                 select new Tuple(t1, t2);
    }
}

UPDATE

Following from NagaMensch's comments, a better way to achieve the desired result would be to use the built in LINQ to SQL associations.

If you go to your entity diagram and click on toolbox, you will see 3 options. Class, Association and Inheritance. We want to use Association.

  • Click on Association and click on the ElectionStatus entity, hold the mouse button down and it will allow you to draw a line to the Election entity.

  • Once you've drawn the line it will ask you which properties are involved in the association. You want to select the StatusId column from the Election entity, and the StatusId column from the ElectionStatus entity.

Now that you've completed your mapping you will be able to simplify your query greatly because the join will not be necessary. You can just access the election status via a brand new property that LINQ to SQL will have added to the Election entity.

Your code can now look like this:

//context has to be moved outside the function
static ExampleDataContext context = new ExampleDataContext();

//Here we can return an IEnumerable of Election now, instead of using the Tuple class
public static IEnumerable<Election> getElections()
{
    return from election in context.Elections
           select election;
}

static void Main(string[] args)
{
    //get the elections
    var elections = getElections();

    //lets go through the elections
    foreach (var election in elections)
    {
        //here we can access election status via the ElectionStatus property
        Console.WriteLine("Election name: {0}; Election status: {1}", election.ElectionName, election.ElectionStatus.StatusDescription);
    }
}

You can also find a "how to" on LINQ to SQL associations here.

Note: It's worth mentioning that if you have an FK relationship set up between your tables in the database; LINQ to SQL will automatically pick the relationship up and map the association for you (therefore creating the properties).

Sign up to request clarification or add additional context in comments.

5 Comments

I'll try it thx. My one concern is that this seems like a db table-center approach, whereas I'd like an architecture that gives me the freedom to query whatever results I need, i.e. they may not even come from a table, etc. So, I guess in that case I would be stuck creating perhaps dozens or even hundreds of these custom objects just to hold data result sets...
New to LINQ and used this same method a few times.
will this retain the integrity of the sql join?
Indeed, you're correct. It would be a terrible idea to implement classes in this style each time you want to return results from a query. In LINQ to SQL you can tell the designer that there is a relationship between the two entities, and it will allow you to access the related entity via a property. That way you can return an Election and then access the status by calling election.election_status. This would be a much better way of doing this and would also maintain the integrity of your join.
I've updated the answer to explain how to use associations to implement a much better solution. If you get stuck at all or need further explanation just let me know :-) I hope this helps.
2

You'll need to create classes that have the same structure as the anonymous types. Then, instead of "new { t1, t2 }", you use "new MyClass(t1, t2)".

Once you have a named class, you can pass it all over the place as you were hoping.

Comments

1

The problem is, that you are creating a anonymous type, hence there is no way to declare a method with this return type. You have to create a new type that will hold your query result and return this type.

But I suggest not to return the result in a new type but return just a colection of election objects and access the election_status objects through the relation properties assuming you included them in your model. The data load options cause the query to include the related election status objects in the query result.

public IList<election> GetElections()
{
    using (ormDataContext context = new ormDataContext(connStr))
    {
        DataLoadOptions dlo = new DataLoadOptions();
        dlo.LoadWith<election>(e => e.election_status);
        context.DeferredLoadingEnabled = false;
        context.LoadOptions = dlo;   
        return context.elections.ToList();
    }
}

Now you can do the following.

IList<election> elections = GetElections();

// Access the election status.
Console.WriteLin(elections[0].election_status);

I general LINQ to SQL could just retrieve the related entities on demand - that is called deferred loading.

ormDataContext context = new ormDataContext(connStr));

IList<election> elections = context.elections.ToList();

// This will trigger a query that loads the election
// status of the first election object.
Console.WriteLine(elections[0].election_status);

But this requires you not to close the data context until you finished using the retrieved objects, hence cannot be used with a using statement encapsulated in a method.

3 Comments

The other alternative is to create the context without the using. This way you won't need to call LoadWith numerous times (depending on the complexity of your query). The side effects of this are that the context won't be automatically disposed, and some queries will be deferred (elections.election_status).
Good timing - just added deferred loading 23 seconds after your comment. ^^
I noticed :) I also hadn't realized you could use LoadWith on the context - I could see that coming in handy. Thanks!
1
IEnumerable<object> getRecordsList()
    {
        using (var dbObj = new OrderEntryDbEntities())
        {
            return (from orderRec in dbObj.structSTIOrderUpdateTbls
                    select orderRec).ToList<object>();
        }
    }

Comments

1

maybe it can help :)

using (ormDataContext context = new ormDataContext(connStr))
{
var electionInfo = from t1 in context.elections
                    join t2 in context.election_status
                    on t1.statusID equals t2.statusID
                    select new { 
                    t1.column1,
                    t1.column2,
                    t1.column3,
                    t1.column4,
                    t2.column5,
                    t2.column6,
                    t2.column7
                    };
}
foreach (var ei in electionInfo){
//write what do u want
}

2 Comments

it says about 7, what if there were less or more?
you can select anything u want in select new{...} just white the column name and the table :)
0
return electionInfo.ToList();

3 Comments

The items selected by the query are of anonymous type. What return type do you sugges if using this return statement? Also, OP doesn't seem to require the data to be stored in a list. Converting to List AFAIK means eagerly reading all items, even if the client does not this. Why a list?
How would you define the List in the calling method? I tried and ran into issues with the List needing a type, but we only have an anonymous type(?)
It must be a List or something like that because the data context is immedeately disposed, hence returning IQueryable or IEnumerable and evaluating the query later will result in an exception due to accessing a disposed object.
0

You cannot return an anonymous type from a method. It is only available within the scope in which it is created. You'll have to create a class instead.

8 Comments

You can return it, but its compile time type will be object.
@Eulerfx, yeah that's what I mean, the type information is gone. Unless you use reflection.
@NagaMensch ... it's not that big of a deal. You just need a class with whatever properties you're anonymous type is returning ... automatic properties make it pretty quick.
Do you really think having to create an object for every single db call is simple? A large project could easily have hundreds of db calls...then when the db changes the code is brittle and needs massive tedious changes.
Whatmight be nice is if I could create a stored proc, drop it onto the LINQ design surface, and have it create an object from the sproc results that could then be easily used anywhere...this whole LINQ concept seems flawed -- tables are not objects, I don't need tables in my code, what I need is data, that is often in a radically different format than my tables. Tables are relational for storing the data, not for using it.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.