Kristina
Kristina

Reputation: 125

Looping to Create and Add New Objects to ArrayList

Edit to save you from reading through this whole post tldr: an object's fields should not be static unless you want all instances of that object to have the same value for that field

I'm trying to create and populate an ArrayList of Blog objects. I do know the generic way do this:

create ArrayList of Blogs
loop (some condition)
     create new Blog
     add this Blog to AL

However, when I attempt to do so within the while(datareader.read()) loop, all of the elements in the ArrayList are exactly the same Blog. Specifically, I end up with an ArrayList filled with multiple pointers to the very last Blog object from the database table. Here is my code:

 public static ArrayList AllBlogs()
    {
        SqlDataReader dr = anonPage.ExecuteReader("SELECT * FROM Kristina_Blogs");

        ArrayList allBlogs = new ArrayList();

        if (dr.HasRows)
        {
            while (dr.Read())
            {
                Blog b = new Blog();

                //grab a row from Kristina_Blogs and assign those attributes to b
                b.setTitle(dr["title"].ToString());
                b.setMessage(dr["message"].ToString());
                b.setId(dr["id"]);

                allBlogs.Add(b);
            }
        }
        dr.Close();
        return allBlogs;
    }

As I said before, the result of this is an ArrayList filled with pointers to the very last blog from the Kristina_Blogs table. I imagine the ArrayList allBlogs looks like [b, b, b, ... b] and therefore they ALL get updated when I say b.setTitle() etc. But how can this be the case if I am creating a NEW Blog object at the beginning of each iteration?


Here is some extra info that you don't have to read but it might clear up some confusion about the structure of the problem:

  1. Blog object has id, title, and message fields and their respective getter/setters
  2. Kristina_Blogs is a table representing these blogs with columns for id, title, message
  3. The suggestions say to include a tag for my DB engine but I can't find a tag for it: Microsoft SQL Server Management Studio
  4. This code works perfectly when I use an ArrayList of Strings instead of Blogs

Edit: Including the code from Blog class

public class Blog
{
    public App myApp;
    public static string Title;
    public static string Message;
    public static int Id;

    //constructors
    public Blog() { }
    public Blog(App App) { this.myApp = App; }

    //all getters and setters look like this
    public string getTitle() { return Title; }
    public void setTitle(string t) { Title = t; }

}

Upvotes: 1

Views: 1256

Answers (4)

Reza Aghaei
Reza Aghaei

Reputation: 125277

The main problem you have, as I mentioned in comments is your member variables are static, so when you set the value, they change in all instances. you should change your code this way:

public class Blog
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Message { get; set; }
}

And fill your list this way, don't forget to add using System.Linq;:

var result = new List<Blog>();
var connection = @"your connection string";
var command = "SELECT * FROM Kristina_Blogs";
var adapter = new System.Data.SqlClient.SqlDataAdapter(command, connection);
var dataTable = new DataTable();

//Get data
adapter.Fill(dataTable);

dataTable.Rows.Cast<DataRow>().ToList()
            .ForEach(row =>
            {
                var b = new Blog();
                b.Id = row.Field<int>("Id");
                b.Title = row.Field<string>("Title");
                b.Message = row.Field<string>("Message");

                result.Add(b);
            });

return result;

Note:

  • When you create a member static, it is shared between all instances of that calss.
  • In C# you can use property to get or set values, you don't need to setX or setY, when you get the value of a property, the get code of that property will execute and when you assign a value to a property the set part of it will execute. you can define properties this way:

Property:

private int id;
public int Id
{
    get
    {
        return id;
    }
    set
    {
        id = value;
    }
}

or more simple:

public int Id { get; set; }

Upvotes: 3

Ron Oravec
Ron Oravec

Reputation: 1

I would make a quick method to prevent null value from throwing error

    public static string GetSafeString(SqlDataReader reader, int index)
    {
        if (!reader.IsDBNull(index))
            return reader.GetString(index);
        else
            return string.Empty;
    }

Replace this code:

        while (dr.Read())
        {
            Blog b = new Blog();

            //grab a row from Kristina_Blogs and assign those attributes to b
            b.setTitle(dr["title"].ToString());
            b.setMessage(dr["message"].ToString());
            b.setId(dr["id"]);

            allBlogs.Add(b);
        }

With This Code:

         while (dr.Read())
        {
            Blog b = new Blog();

            //grab a row from Kristina_Blogs and assign those attributes to b
            b.setId(dr.GetInt32(0));
            b.setTitle(GetSafeString(dr, 1);
            b.setMessage(GetSafeString(dr, 2);
            allBlogs.Add(b);
        }

Where the number is the index of field in the record and assuming "id" is an integer. Also consider moving creation of "Blog" object outside of loop and just change values.

Upvotes: 0

Sterls
Sterls

Reputation: 761

Remove the static attributes from your class:

public class Blog
{
   public App myApp;
   public String Title;
   public String Message;
   public int Id;

//constructors
public Blog() { }
public Blog(App App) { this.myApp = App; }

//all getters and setters look like this
public String getTitle() { return Title; }
public String getMessage() { return Message; }
public void setTitle(String t) { Title = t; }
public void setMessage(String m) { Message = m; }    

}

When you use static variables, all instances of an object will contain the same values in those variables. By removing the static keyword, you are allowing different instances of the object to hold different values.

Now, every time you create a blog object, that object's Title and Message etc, will contain its own information.

Upvotes: 0

Servy
Servy

Reputation: 203829

All of the fields in your Blog class are static, meaning they're shared between all object instances. You want them to be instance field (meaning not static) so that each object has its own copy of each of those values.

Upvotes: 2

Related Questions