简体   繁体   中英

Entity Framework avoid LazyLoading / already open DataReader issue

With an Union Query which runs several times successively I get UserlistSection objects for each alphabetic letter, if Users exist with the starting letter. So I get something like this:

  • UserlistSection "A"
    • User
    • User
  • UserlistSection "H"
    • User
  • UserlistSection "Y"
    • User
    • User
    • User

But the query throws following exception

MySql.Data.MySqlClient.MySqlException: There is already an open DataReader associated with this Connection which must be closed first.

The query Task

public UserRepository(myDatabase database)
    {
        _database = database;
    }

public Task<ObservableCollection<User>> GetUserFriendsAsync(int id, string letter)
    {
        return Task.Factory.StartNew(() =>
        {
            try
            {
                var query1 = (from urs in _database.user_relationships
                              join u in _database.users on urs.relationship_user_from equals u.user_id
                              where urs.relationship_user_to == id
                                    && u.user_name.StartsWith(letter)
                                    && urs.relationship_status == 1
                              select new User
                              {
                                  Id = u.user_id,
                                  Username = u.user_name,
                                  AvatarByte = u.user_avatar,
                                  Gender = u.user_gender,
                                  GroupId = u.user_usergroup,
                                  LoginStatusId = u.user_loginstatus
                              });

                var query2 = (from urs in _database.user_relationships
                              join u in _database.users on urs.relationship_user_to equals u.user_id
                              where urs.relationship_user_from == id
                                    && u.user_name.StartsWith(letter)
                                    && urs.relationship_status == 1
                              select new User
                              {
                                  Id = u.user_id,
                                  Username = u.user_name,
                                  AvatarByte = u.user_avatar,
                                  Gender = u.user_gender,
                                  GroupId = u.user_usergroup,
                                  LoginStatusId = u.user_loginstatus
                              });

                // Union to get users via relationships (from - to and to - from)
                var queryUnion = query1.Union(query2).OrderBy(u => u.Username);

                return new ObservableCollection<User>(queryUnion);
            }
            catch (Exception ex)
            {
                Trace.WriteLine("UserRepository - GetUserFriendsAsync" + ex);
                return null;
            }
        });
    }

And my Object / Method to create the Collection

public class UserlistSection : ObservableObject
{
    #region Attributes

    private string _letter;
    private ObservableCollection<User> _users;

    #endregion Attributes

    public string Letter
    {
        get { return _letter; }
        set { Set(ref _letter, value); }
    }

    public ObservableCollection<User> Users
    {
        get { return _users; }
        set { Set(ref _users, value); }
    }
}

// -------------------------------------------------------------------------

 public async void UpdateFriendlistCollection()
    {
        IsLoading = true;
        Friendlist = new ObservableCollection<UserlistSection>();

        for (var c = 'A'; c <= 'Z'; c++)
        {
            try
            {
                var letter = c.ToString();
                var userCollection = await _userRepository.GetUserFriendsAsync(_userObj.Id, letter);

                if (userCollection.Count < 1) return;

                foreach (var friend in userCollection)
                {
                    friend.AvatarImage = friend.GetAvatarImgByPixel(200);
                }

                var section = new UserlistSection
                {
                    Letter = letter,
                    Users = userCollection
                };

                Friendlist.Add(section);
            }
            catch (Exception ex)
            {
                Trace.WriteLine("FriendlistViewModel - UpdateFriendlistCollection: " + ex.Message);
            }
        }

        IsLoading = false;
    }

There are probably better ways to build the query, but I couldn't figure out how yet. So would be nice if someone can see my mistakes to avoid the LazyLoading / solve the exception.

If I'm missing some explanation, please just tell.

Edit

When I add MultipleActiveResultSets=True like that, it tells me that the keyword isn't support?

<connectionStrings>
<add name="someDatabase"   connectionString="metadata=res://*/Repository.Database.SomeDatabase.csdl|res://*/Repository.Database.SomeDatabase.ssdl|res://*/Repository.Database.SomeDatabase.msl;provider=MySql.Data.MySqlClient;provider connection string=&quot;server=127.0.0.1;user id=someUser;persistsecurityinfo=True;password=somePassword;multipleactiveresultsets=True;database=someDatabase;&quot;" providerName="System.Data.EntityClient" />

System.ArgumentException: Keyword not supported.
Parametername: multipleactiveresultsets
bei MySql.Data.MySqlClient.MySqlConnectionStringBuilder.GetOption(String key)
bei MySql.Data.MySqlClient.MySqlConnectionStringBuilder.set_Item(String  keyword, Object value)

You should enable MARS in your connectionstring in config.

Add "MultipleActiveResultSets=True" to connection string.

More info .

EDIT

From MSDN :

When you call the Load method during a foreach (C#) or For Each (Visual Basic) enumeration, the Entity Framework tries to open a new data reader. This operation will fail unless you have enabled multiple active results sets by specifying multipleactiveresultsets=true in the connection string. For more information, see Using Multiple Active Result Sets (MARS) on MSDN. You can also load the result of the query into a List collection, which closes the data reader and enables you to enumerate over the collection to load referenced entities

EDIT

For MySQL i found this . Mayby it helps you.

It seems that MySQL does not support MARS. If you can change the database for MS SQL Server Express. Or change the ORM for example NHibernate.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM